I'm learning functional programming with F#, and I want to write a function that will generate a sequence for me.
There is a some predetermined function for transforming a value, and in the function I need to write there should be two inputs - the starting value and the length of the sequence. Sequence starts with the initial value, and each following item is a result of applying the transforming function to the previous value in the sequence.
In C# I would normally write something like that:
public static IEnumerable<double> GenerateSequence(double startingValue, int n)
{
double TransformValue(double x) => x * 0.9 + 2;
yield return startingValue;
var returnValue = startingValue;
for (var i = 1; i < n; i++)
{
returnValue = TransformValue(returnValue);
yield return returnValue;
}
}
As I tried to translate this function to F#, I made this:
let GenerateSequence startingValue n =
let transformValue x =
x * 0.9 + 2.0
seq {
let rec repeatableFunction value n =
if n = 1 then
transformValue value
else
repeatableFunction (transformValue value) (n-1)
yield startingValue
for i in [1..n-1] do
yield repeatableFunction startingValue i
}
There are two obvious problems with this implementation.
First is that because I tried to avoid making a mutable value (analogy of returnValue variable in C# implementation), I didn't reuse values of former computations while generating sequence. This means that for the 100th element of the sequence I have to make additional 99 calls of the transformValue function instead of just one (as I did in C# implementation). This reeks with extremely bad performance.
Second is that the whole function does not seem to be written in accordance with Functional Programming. I am pretty sure that there are more elegant and compact implementation. I suspect that Seq.fold or List.fold or something like that should have been used here, but I'm still not able to grasp how to effectively use them.
So the question is: how to re-write the GenerateSequence function in F# so it would be in Functional Programming style and have a better performance?
Any other advice would also be welcomed.
The answer from #rmunn shows a rather nice solution using unfold. I think there are other two options worth considering, which are actually just using a mutable variable and using a recursive sequence expression. The choice is probably a matter of personal preference. The two other options look like this:
let generateSequenceMutable startingValue n = seq {
let transformValue x = x * 0.9 + 2.0
let mutable returnValue = startingValue
for i in 1 .. n do
yield returnValue
returnValue <- transformValue returnValue }
let generateSequenceRecursive startingValue n =
let transformValue x = x * 0.9 + 2.0
let rec loop value i = seq {
if i < n then
yield value
yield! loop (transformValue value) (i + 1) }
loop startingValue 0
I modified your logic slightly so that I do not have to yield twice - I just do one more step of the iteration and yield before updating the value. This makes the generateSequenceMutable function quite straightforward and easy to understand. The generateSequenceRecursive implements the same logic using recursion and is also fairly nice, but I find it a bit less clear.
If you wanted to use one of these versions and generate an infinite sequence from which you can then take as many elements as you need, you can just change for to while in the first case or remove the if in the second case:
let generateSequenceMutable startingValue n = seq {
let transformValue x = x * 0.9 + 2.0
let mutable returnValue = startingValue
while true do
yield returnValue
returnValue <- transformValue returnValue }
let generateSequenceRecursive startingValue n =
let transformValue x = x * 0.9 + 2.0
let rec loop value i = seq {
yield value
yield! loop (transformValue value) (i + 1) }
loop startingValue 0
If I was writing this, I'd probably go either with the mutable variable or with unfold. Mutation may be "generally evil" but in this case, it is a localized mutable variable that is not breaking referential transparency in any way, so I don't think it's harmful.
Your description of the problem was excellent: "Sequence starts with the initial value, and each following item is a result of applying the transforming function to the previous value in the sequence."
That is a perfect description of the Seq.unfold method. It takes two parameters: the initial state and a transformation function, and returns a sequence where each value is calculated from the previous state. There are a few subtleties involved in using Seq.unfold which the rather terse documentation may not explain very well:
Seq.unfold expects the transformation function, which I'll call f from now on, to return an option. It should return None if the sequence should end, or Some (...) if there's another value left in the sequence. You can create infinite sequences this way if you never return None; infinite sequences are perfectly fine since F# evaluates sequences lazily, but you do need to be careful not to ever loop over the entirely of an infinite sequence. :-)
Seq.unfold also expects that if f returns Some (...), it will return not just the next value, but a tuple of the next value and the next state. This is shown in the Fibonacci example in the documentation, where the state is actually a tuple of the current value and the previous value, which will be used to calculate the next value shown. The documentation example doesn't make that very clear, so here's what I think is a better example:
let infiniteFibonacci = (0,1) |> Seq.unfold (fun (a,b) ->
// a is the value produced *two* iterations ago, b is previous value
let c = a+b
Some (c, (b,c))
)
infiniteFibonacci |> Seq.take 5 |> List.ofSeq // Returns [1; 2; 3; 5; 8]
let fib = seq {
yield 0
yield 1
yield! infiniteFibonacci
}
fib |> Seq.take 7 |> List.ofSeq // Returns [0; 1; 1; 2; 3; 5; 8]
And to get back to your GenerateSequence question, I would write it like this:
let GenerateSequence startingValue n =
let transformValue x =
let result = x * 0.9 + 2.0
Some (result, result)
startingValue |> Seq.unfold transformValue |> Seq.take n
Or if you need to include the starting value in the sequence:
let GenerateSequence startingValue n =
let transformValue x =
let result = x * 0.9 + 2.0
Some (result, result)
let rest = startingValue |> Seq.unfold transformValue |> Seq.take n
Seq.append (Seq.singleton startingValue) rest
The difference between Seq.fold and Seq.unfold
The easiest way to remember whether you want to use Seq.fold or Seq.unfold is to ask yourself which of these two statements is true:
I have a list (or array, or sequence) of items, and I want to produce a single result value by running a calculation repeatedly on pairs of items in the list. For example, I want to take the product of this whole series of numbers. This is a fold operation: I take a long list and "compress" it (so to speak) until it's a single value.
I have a single starting value and a function to produce the next value from the current value, and I want to end up with a list (or sequence, or array) of values. This is an unfold operation: I take a small starting value and "expand" it (so to speak) until it's a whole list of values.
Related
I am absolute OCaml beginner. I want to create a function that repeats characters 20 times.
This is the function, but it does not work because of an error.
let string20 s =
let n = 20 in
s ^ string20 s (n - 1);;
string20 "u";;
I want to run like this
# string20 "u"
- : string = "uuuuuuuuuuuuuuuuuuuu"
Your function string20 takes one parameter but you are calling it recursively with 2 parameters.
The basic ideas are in there, but not quite in the right form. One way to proceed is to separate out the 2-parameter function as a separate "helper" function. As #PierreG points out, you'll need to delcare the helper function as a recursive function.
let rec string n s =
if n = 0 then "" else s ^ string (n - 1) s
let string20 = string 20
It is a common pattern to separate a function into a "fixed" part and inductive part. In this case, a nested helper function is needed to do the real recursive work in a new scope while we want to fix an input string s as a constant so we can use to append to s2. s2 is an accumulator that build up the train of strings over time while c is an inductor counting down to 1 toward the base case.
let repeat s n =
let rec helper s1 n1 =
if n1 = 0 then s1 else helper (s1 ^ s) (n1 - 1)
in helper "" n
A non-tail call versions is more straightforward since you won't need a helper function at all:
let rec repeat s n =
if n = 0 then "" else s ^ repeat s (n - 1)
On the side note, one very fun thing about a functional language with first-class functions like Ocaml is currying (or partial application). In this case you can create a function named repeat that takes two arguments n of type int and s of type string as above and partially apply it to either n or s like this:
# (* top-level *)
# let repeat_foo = repeat "foo";;
# repeat_foo 5;;
- : bytes = "foofoofoofoofoo" (* top-level output *)
if the n argument was labeled as below:
let rec repeat ?(n = 0) s =
if n = 0 then "" else s ^ repeat s (n - 1)
The order of application can be exploited, making the function more flexible:
# (* top-level *)
# let repeat_10 = repeat ~n:10;;
# repeat_10 "foo";;
- : bytes = "foofoofoofoofoofoofoofoofoofoo" (* top-level output *)
See my post Currying Exercise in JavaScript (though it is in JavaScript but pretty simple to follow) and this lambda calculus primer.
Recursive functions in Ocaml are defined with let rec
As pointed out in the comments you've defined your function to take one parameter but you're trying to recursively call with two.
You probably want something like this:
let rec stringn s n =
match n with
1 -> s
| _ -> s ^ stringn s (n - 1)
;;
How does one get the first key,value pair from F# Map without knowing the key?
I know that the Map type is used to get a corresponding value given a key, e.g. find.
I also know that one can convert the map to a list and use List.Head, e.g.
List.head (Map.toList map)
I would like to do this
1. without a key
2. without knowing the types of the key and value
3. without using a mutable
4. without iterating through the entire map
5. without doing a conversion that iterates through the entire map behind the seen, e.g. Map.toList, etc.
I am also aware that if one gets the first key,value pair it might not be of use because the map documentation does not note if using map in two different calls guarantees the same order.
If the code can not be written then an existing reference from a site such as MSDN explaining and showing why not would be accepted.
TLDR;
How I arrived at this problem was converting this function:
let findmin l =
List.foldBack
(fun (_,pr1 as p1) (_,pr2 as p2) -> if pr1 <= pr2 then p1 else p2)
(List.tail l) (List.head l)
which is based on list and is used to find the minimum value in the associative list of string * int.
An example list:
["+",10; "-",10; "*",20; "/",20]
The list is used for parsing binary operator expressions that have precedence where the string is the binary operator and the int is the precedence. Other functions are preformed on the data such that using F# map might be an advantage over list. I have not decided on a final solution but wanted to explore this problem with map while it was still in the forefront.
Currently I am using:
let findmin m =
if Map.isEmpty m then
None
else
let result =
Map.foldBack
(fun key value (k,v) ->
if value <= v then (key,value)
else (k,v))
m ("",1000)
Some(result)
but here I had to hard code in the initial state ("",1000) when what would be better is just using the first value in the map as the initial state and then passing the remainder of the map as the starting map as was done with the list:
(List.tail l) (List.head l)
Yes this is partitioning the map but that did not work e.g.,
let infixes = ["+",10; "-",10; "*",20; "/",20]
let infixMap = infixes |> Map.ofList
let mutable test = true
let fx k v : bool =
if test then
printfn "first"
test <- false
true
else
printfn "rest"
false
let (first,rest) = Map.partition fx infixMap
which results in
val rest : Map<string,int> = map [("*", 20); ("+", 10); ("-", 10)]
val first : Map<string,int> = map [("/", 20)]
which are two maps and not a key,value pair for first
("/",20)
Notes about answers
For practical purposes with regards to the precedence parsing seeing the + operations before - in the final transformation is preferable so returning + before - is desirable. Thus this variation of the answer by marklam
let findmin (map : Map<_,_>) = map |> Seq.minBy (fun kvp -> kvp.Value)
achieves this and does this variation by Tomas
let findmin m =
Map.foldBack (fun k2 v2 st ->
match st with
| Some(k1, v1) when v1 < v2 -> st
| _ -> Some(k2, v2)) m None
The use of Seq.head does return the first item in the map but one must be aware that the map is constructed with the keys sorted so while for my practical example I would like to start with the lowest value being 10 and since the items are sorted by key the first one returned is ("*",20) with * being the first key because the keys are strings and sorted by such.
For me to practically use the answer by marklam I had to check for an empty list before calling and massage the output from a KeyValuePair into a tuple using let (a,b) = kvp.Key,kvp.Value
I don't think there is an answer that fully satisfies all your requirements, but:
You can just access the first key-value pair using m |> Seq.head. This is lazy unlike converting the map to list. This does not guarantee that you always get the same first element, but realistically, the implementation will guarantee that (it might change in the next version though).
For finding the minimum, you do not actually need the guarantee that Seq.head returns the same element always. It just needs to give you some element.
You can use other Seq-based functons as #marklam mentioned in his answer.
You can also use fold with state of type option<'K * 'V>, which you can initialize with None and then you do not have to worry about finding the first element:
m |> Map.fold (fun st k2 v2 ->
match st with
| Some(k1, v1) when v1 < v2 -> st
| _ -> Some(k2, v2)) None
Map implements IEnumerable<KeyValuePair<_,_>> so you can treat it as a Seq, like:
let findmin (map : Map<_,_>) = map |> Seq.minBy (fun kvp -> kvp.Key)
It's even simpler than the other answers. Map internally uses an AVL balanced tree so the entries are already ordered by key. As mentioned by #marklam Map implements IEnumerable<KeyValuePair<_,_>> so:
let m = Map.empty.Add("Y", 2).Add("X", 1)
let (key, value) = m |> Seq.head
// will return ("X", 1)
It doesn't matter what order the elements were added to the map, Seq.head can operate on the map directly and return the key/value mapping for the min key.
Sometimes it's required to explicitly convert Map to Seq:
let m = Map.empty.Add("Y", 2).Add("X", 1)
let (key, value) = m |> Map.toSeq |> Seq.head
The error message I've seen for this case says "the type 'a * 'b does not match the type Collections.Generic.KeyValuePair<string, int>". It may also be possible add type annotations rather than Map.toSeq.
I'm trying to write some code in a functional paradigm for practice. There is one case I'm having some problems wrapping my head around. I am trying to create an array of 5 unique integers from 1, 100. I have been able to solve this without using functional programming:
let uniqueArray = [];
while (uniqueArray.length< 5) {
const newNumber = getRandom1to100();
if (uniqueArray.indexOf(newNumber) < 0) {
uniqueArray.push(newNumber)
}
}
I have access to lodash so I can use that. I was thinking along the lines of:
const uniqueArray = [
getRandom1to100(),
getRandom1to100(),
getRandom1to100(),
getRandom1to100(),
getRandom1to100()
].map((currentVal, index, array) => {
return array.indexOf(currentVal) > -1 ? getRandom1to100 : currentVal;
});
But this obviously wouldn't work because it will always return true because the index is going to be in the array (with more work I could remove that defect) but more importantly it doesn't check for a second time that all values are unique. However, I'm not quite sure how to functionaly mimic a while loop.
Here's an example in OCaml, the key point is that you use accumulators and recursion.
let make () =
Random.self_init ();
let rec make_list prev current max accum =
let number = Random.int 100 in
if current = max then accum
else begin
if number <> prev
then (number + prev) :: make_list number (current + 1) max accum
else accum
end
in
make_list 0 0 5 [] |> Array.of_list
This won't guarantee that the array will be unique, since its only checking by the previous. You could fix that by hiding a hashtable in the closure between make and make_list and doing a constant time lookup.
Here is a stream-based Python approach.
Python's version of a lazy stream is a generator. They can be produced in various ways, including by something which looks like a function definition but uses the key word yield rather than return. For example:
import random
def randNums(a,b):
while True:
yield random.randint(a,b)
Normally generators are used in for-loops but this last generator has an infinite loop hence would hang if you try to iterate over it. Instead, you can use the built-in function next() to get the next item in the string. It is convenient to write a function which works something like Haskell's take:
def take(n,stream):
items = []
for i in range(n):
try:
items.append(next(stream))
except StopIteration:
return items
return items
In Python StopIteration is raised when a generator is exhausted. If this happens before n items, this code just returns however much has been generated, so perhaps I should call it takeAtMost. If you ditch the error-handling then it will crash if there are not enough items -- which maybe you want. In any event, this is used like:
>>> s = randNums(1,10)
>>> take(5,s)
[6, 6, 8, 7, 2]
of course, this allows for repeats.
To make things unique (and to do so in a functional way) we can write a function which takes a stream as input and returns a stream consisting of unique items as output:
def unique(stream):
def f(s):
items = set()
while True:
try:
x = next(s)
if not x in items:
items.add(x)
yield x
except StopIteration:
raise StopIteration
return f(stream)
this creates an stream in a closure that contains a set which can keep track of items that have been seen, only yielding items which are unique. Here I am passing on any StopIteration exception. If the underlying generator has no more elements then there are no more unique elements. I am not 100% sure if I need to explicitly pass on the exception -- (it might happen automatically) but it seems clean to do so.
Used like this:
>>> take(5,unique(randNums(1,10)))
[7, 2, 5, 1, 6]
take(10,unique(randNums(1,10))) will yield a random permutation of 1-10. take(11,unique(randNums(1,10))) will never terminate.
This is a very good question. It's actually quite common. It's even sometimes asked as an interview question.
Here's my solution to generating 5 integers from 0 to 100.
let rec take lst n =
if n = 0 then []
else
match lst with
| [] -> []
| x :: xs -> x :: take xs (n-1)
let shuffle d =
let nd = List.map (fun c -> (Random.bits (), c)) d in
let sond = List.sort compare nd in
List.map snd sond
let rec range a b =
if a >= b then []
else a :: range (a+1) b;;
let _ =
print_endline
(String.concat "\t" ("5 random integers:" :: List.map string_of_int (take (shuffle (range 0 101)) 5)))
How's this:
const addUnique = (ar) => {
const el = getRandom1to100();
return ar.includes(el) ? ar : ar.concat([el])
}
const uniqueArray = (numberOfElements, baseArray) => {
if (numberOfElements < baseArray.length) throw 'invalid input'
return baseArray.length === numberOfElements ? baseArray : uniqueArray(numberOfElements, addUnique(baseArray))
}
const myArray = uniqueArray(5, [])
The problem I'm working on needs to take in a list of integers and return the average of those numbers. It needs to fit a specific format that looks like this...
fun average (n::ns) =
let
val (a,b) = fold? (?) ? ?
in
real(a) / real(b)
end;
I'm only allowed to replace the question marks and cannot used any built in functions. I have a working solution, but it doesn't adhere to these rules.
fun average (n::ns) =
let
val (a,b) = ((foldl (fn(x, y)=>(x+y)) n ns), length(ns)+1)
in
real(a) / real(b)
end;
So, is there a way to make a fold function return a tuple? Something like this is what I want it to do, but obviously I can't do this...
val (a,b) = ((foldl (fn(x, y)=>(x+y), count++) n ns)
Return type of foldl is the type of the initial accummulator. So the idea here is to provide a tuple including sum and count of elements in the list:
fun average (n::ns) =
let
val (a, b) = foldl (fn (x, (sum, count)) => (sum+x, count+1)) (n, 1) ns
in
real(a) / real(b)
end
Notice that your solution fails if the list is empty, it's better to add another case of handling empty list (either returning 0.0 or throwing a custom exception):
fun average [] = 0.0
| average (n::ns) = (* the same as above *)
I'm new to ocaml and tryin to write a continuation passing style function but quite confused what value i need to pass into additional argument on k
for example, I can write a recursive function that returns true if all elements of the list is even, otherwise false.
so its like
let rec even list = ....
on CPS, i know i need to add one argument to pass function
so like
let rec evenk list k = ....
but I have no clue how to deal with this k and how does this exactly work
for example for this even function, environment looks like
val evenk : int list -> (bool -> ’a) -> ’a = <fun>
evenk [4; 2; 12; 5; 6] (fun x -> x) (* output should give false *)
The continuation k is a function that takes the result from evenk and performs "the rest of the computation" and produces the "answer". What type the answer has and what you mean by "the rest of the computation" depends on what you are using CPS for. CPS is generally not an end in itself but is done with some purpose in mind. For example, in CPS form it is very easy to implement control operators or to optimize tail calls. Without knowing what you are trying to accomplish, it's hard to answer your question.
For what it is worth, if you are simply trying to convert from direct style to continuation-passing style, and all you care about is the value of the answer, passing the identity function as the continuation is about right.
A good next step would be to implement evenk using CPS. I'll do a simpler example.
If I have the direct-style function
let muladd x i n = x + i * n
and if I assume CPS primitives mulk and addk, I can write
let muladdk x i n k =
let k' product = addk x product k in
mulk i n k'
And you'll see that the mulptiplication is done first, then it "continues" with k', which does the add, and finally that continues with k, which returns to the caller. The key idea is that within the body of muladdk I allocated a fresh continuation k' which stands for an intermediate point in the multiply-add function. To make your evenk work you will have to allocate at least one such continuation.
I hope this helps.
Whenever I've played with CPS, the thing passed to the continuation is just the thing you would normally return to the caller. In this simple case, a nice "intuition lubricant" is to name the continuation "return".
let rec even list return =
if List.length list = 0
then return true
else if List.hd list mod 2 = 1
then return false
else even (List.tl list) return;;
let id = fun x -> x;;
Example usage: "even [2; 4; 6; 8] id;;".
Since you have the invocation of evenk correct (with the identity function - effectively converting the continuation-passing-style back to normal style), I assume that the difficulty is in defining evenk.
k is the continuation function representing the rest of the computation and producing a final value, as Norman said. So, what you need to do is compute the result of v of even and pass that result to k, returning k v rather than just v.
You want to give as input the result of your function as if it were not written with continuation passing style.
Here is your function which tests whether a list has only even integers:
(* val even_list : int list -> bool *)
let even_list input = List.for_all (fun x -> x mod 2=0) input
Now let's write it with a continuation cont:
(* val evenk : int list -> (bool -> 'a) -> 'a *)
let evenk input cont =
let result = even_list input in
(cont result)
You compute the result your function, and pass resultto the continuation ...