I am actually sitting over a hour on a problem and donĀ“t find a solution for it.
I have this data type:
type 'a tree = Empty | Node of 'a * 'a tree * 'a tree
And i have to find a function which converts a given tree in a ordered list. There is also no invariant like that the left child has to be less then the right. I already found a "normal" recursion solution but not a tail recursive solution. I already thought about to build a unordered list and sort it with List.sort, but this uses a merge sort which is not tail recursive. Maybe someone has a good advice.
Thank you!
If you want to traverse the tree in order and return a list, that means our function inorder must have the type 'a tree -> 'a list.
let rec inorder t =
match t with
| Empty -> []
| Node (v, l, r) -> List.append (inorder l) (v :: (inorder r)) (* ! *)
However List.append is in tail position, not inorder. Another problem is we have two calls to inorder. If we put inorder l in tail position, inorder r could not possibly be in tail position - and vice versa.
A neat way to work around this problem is continuation passing style. We take our function above and convert it into a helper function with an extra parameter for our continuation, return
(* convert to helper function, add an extra parameter *)
let rec loop t return =
match t with
| Empty -> ...
| Node (v, l, r) -> ...
The continuation represents "what to do next", so instead of sending values directly out of our function, we must hand them to the continuation instead. That means for the Empty case, we'll return [] - instead of simply []
let rec loop t return =
match t with
| Empty -> return []
| Node (v, l, r) -> ...
For the Node (v, l, r) case, now that we have an extra parameter we can write our own continuation that informs loop what to do next. So to construct our sorted list, we will need to loop l, then loop r (or vice versa), then we can append them. We'll write our program just like this.
let rec loop t return =
match t with
| Empty -> return []
| Node (v, l, r) ->
loop l ... (* build the left_result *)
loop r ... (* build the right_result *)
return (List.append left_result (v :: right_result))
In this next step, we'll fill in the actual lambda syntax for the continuations.
let rec loop t return =
match t with
| Empty -> return []
| Node (v, l, r) ->
loop l (fun left ->
loop r (fun right ->
return (List.append left (v :: right))))
Last, we define inorder which is a call to loop with the default continuation, identity.
let identity x =
x
let inorder t =
let rec loop t return =
match t with
| Empty -> return []
| Node (v, l, r) ->
loop r (fun right ->
loop l (fun left ->
return (List.append left (v :: right))))
in
loop t identity
As you can see loop r (fun right -> ...) is in tail position for the Node branch. loop l (fun left -> ...) is in tail position of the first continuation. And List.append ... is in tail position of the second continuation. Provided List.append is a tail-recursive procedure, inorder will not grow the stack.
Note using List.append could be a costly choice for big trees. Our function calls it once per Node. Can you think of a way to avoid it? This exercise is left for the reader.
Related
I am trying to iterate through a stream in order to print the content.
type 'a stream = Nil | Cons of 'a * 'a stream thunk and 'a thunk = unit -> 'a
This is where my function is called
|> iter_stream ~f:(fun (f,c,l) -> printf "%s %s %s\n" f c l)
And this is the type
let rec iter_stream st ~f
(* val iter_stream : 'a stream -> ('a -> unit) -> unit *)
I can't seem to find any examples on how to implement it. The only idea I have is to think about it like a list which is obviously wrong since I get type errors.
let rec iter_stream st ~f =
match st with
| None -> ()
| Some(x, st') -> f x; iter_stream st' ~f
Your stream is extremely similar to a list, except that you need to call a function to get the tail of the list.
Your proposed code has many flaws. The main two flaws that I see are:
You're using the constructors None and Some while a stream has constructors Nil and Cons.
You're not calling a function to get the tail of the stream. Note that in Cons (a, b), b is a "stream thunk", i.e., it's a function that you can call to get a stream.
(Perhaps these are the only two flaws :-)
I hope this helps.
This is my function
let rec helper inputList = function
| [] -> []
| a :: b :: hd ->
if a = b then helper ([b::hd])
else a :: helper (b::hd)
It's not complete, however I can't see why I keep getting the error in the title at helper ([b::hd]). I've tried helper (b::hd) or helper (b::hd::[]) however all come up with errors. How do I make it so that it works?
When you use function you are supplying a pattern for the parameter of the function. But you already have a parameter named inputList. So this function helper is expecting two parameters (but it ignores the first).
You can fix this by removing inputList.
You also have a problem in your first recursive call to helper. Your expression [b :: hd] is a list of lists. I suspect that you want something more like just b :: hd here.
There is at least one other problem, but I hope this helps get you started.
There are multiple errors here. One is that the keyword function means we have an implicit parameter over which we are working. So the pattern matching happens on that "invisible" parameter. But here you defined probably the explicit one: inputList. So we can remove that one:
let rec helper = function
| [] -> []
| a :: b :: hd -> if a = b then helper ([b::hd]) else a :: helper (b:: hd)
Next there is a problem with the types: in the recursion, you use:
helper ([b::hd]); and
a :: helper (b:: hd)
But you put these on the same line, and that makes no sense, since the first one passes a list of lists of elements, and the second a list of elements. So the result of the first one would be a list of list of elements, and the second one a list of elements. It does not make sense to merge these.
If I understood correctly that you want to ensure that no two consecutive elements should occur that are equal, then we should rewrite it to:
let rec helper = function
| [] -> []
| a :: b :: hd -> if a = b then helper (b::hd) else a :: helper (b:: hd)
You have defined two patterns here:
one for the empty list; and
one for a list with at least two elements.
The second one will perform recursion on the tail of the list b :: hd. So that means that eventually when we pass it a list with n elements, it will recursively work on a list with n-1 elements, n-2 elements, etc. But eventually it will have one element. And there is no case for that. So we need to add a case for the one element pattern:
let rec helper = function
| [] -> []
| h :: [] -> h :: []
| a :: b :: hd -> if a = b then helper (b::hd) else a :: helper (b:: hd)
I'm looking at the code in the F# 'Tutorial' template that is provided with Visual Studio 2015 and I see this code; I'm wondering why the first function isn't tail-recursive; I think I understand it but want to confirm:
/// Computes the sum of a list of integers using recursion.
let rec sumList xs =
match xs with
| [] -> 0
| y::ys -> y + sumList ys
/// Make the function tail recursive, using a helper function with a result accumulator
let rec private sumListTailRecHelper accumulator xs =
match xs with
| [] -> accumulator
| y::ys -> sumListTailRecHelper (accumulator+y) ys
Is the first one not tail recursive in the because '+' is a function and its' two arguments are evaluated first? Therefore the actual order of evaluation would be: y, then sumList ys, then +? Whereas in the second case, the order of evaluation is: accumulator,y,+ then sumListTailRecHelper(..)?
A call is tail-recursive if there's nothing left to do after the recursive call returns. So the last call amounts to going back to the start of the function code, with modified parameters.
In the first function you still have to add y to the result.
I've started learning F# and I'd like to write my own map function using tail-recursion. Here is what I have
let my_map ff list =
let rec mapAcc ff_inner list_inner acc =
match list_inner with
| [] -> acc
| front::rest -> mapAcc( ff_inner rest (ff_inner(front) :: acc) ) //error
mapAcc ff list []
It would be called like this:
let list = my_map (fun x -> x * 2) [1;2;3;4;5] // expect [2;4;6;8;10]
I get an compilation error message on the second condition that says Type mismatch. Expecting a 'a but given a 'b list -> 'a -> 'a The resulting type would be infinite when unifying ''a' and ''b list -> 'a -> 'a'
I don't know what this error message means. I'm not sure how this can be infinite if I am passing the rest in the recursive call to mapAcc.
Note: I realize I'm rebuilding the list backwards. I'm ignoring that for now.
Just remove the parenthesis when the function calls itself:
let my_map ff list =
let rec mapAcc ff_inner list_inner acc =
match list_inner with
| [] -> acc
| front::rest -> mapAcc ff_inner rest (ff_inner(front) :: acc)
mapAcc ff list []
otherwise everything contained there is interpreted as a single parameter and ff_inner as a function call with the rest as parameters.
fighting with f# - the fight is in the realm of Trees - specifically to count the number of nodes. This is of real interest as the program I would like to eventually code in F# concerns multi-way trees, unfortunately it has got off to a bit of a troublesome start - I hope you maybe able to help!
Problem 61 of the 99 f# series, asks to count the leaves of a binary Tree. The solution (given below) counts the nodes, but my problem is not understanding
how the double recursion works loop left (fun lacc -> loop right..)
what cont (branchF x lacc racc) is, my impression was that cont was the "abc" function, but this takes only two parameters...
loop t id the id is of type unit - i don't see how this is implied
basically not understanding this, or the order in which it flows through the tree (debug & step through not proving helpful) If there are simpler examples, pre-reading recommendations etc. then please direct me to them.
Many thanks for any help, the solution code in question is below:
Cheers
td
type 'a Tree = Empty | Branch of 'a * 'a Tree * 'a Tree
let foldTree branchF emptyV t =
let rec loop t cont =
match t with
| Empty ->
cont emptyV
| Branch (x, left, right) ->
loop left (fun lacc ->
loop right (fun racc ->
cont (branchF x lacc racc)))
loop t id
let counLeaves tree =
foldTree (fun abc lc rc ->
if lc + rc = 0 then 1
else 1 + lc + rc) 0 tree
let Tree1 = Branch ('x', Branch ('x', Empty, Empty),Branch ('x', Empty, Branch ('x', Empty, Branch ('x', Empty, Empty))))
let result = counLeaves Tree1
As the name implies, foldTree defines the fold function over the custom Tree type.
A naive way of defining a foldTree could be:
let rec foldTreeNaive accFun init = function
| Empty -> init
| Branch (x, left, right) ->
let lacc = foldTreeNaive accFun init left
let racc = foldTreeNaive accFun init right
accFun x lacc racc
The problem with this function is that it could potential make very deep recursive calls if the tree being folded over is deep, since the recursive calls must complete for a node before the accumulator function can be called. For example the following causes a stack overflow exception:
let unbalanced = [1..100000] |> List.fold (fun t i -> Branch(i, t, Empty)) Empty
let nodeCount = foldTreeNaive (fun _ lc rc -> lc + rc + 1) 0 unbalanced
The usual way to avoid such stack overflows is to make the function tail recursive, however this seems impossible in this case since there are two recursive calls to make, instead of the one required when folding over lists.
foldTree is defined using the local loop function. This function is interesting in that it is defined using continuation passing style. In CPS, each function takes an additional 'continuation' function which is passed the result of the computation and is responsible for deciding what happens next. Note that loop is tail recursive and so avoids the overflow problem of foldTreeNaive.
The type of the loop function is:
Tree<'a> -> ('b -> 'c) -> 'c
where 'a is the type of nodes in the tree, 'b is the accumulator type, and 'c is the result of the continuation function.
In the case of a leaf node, the continuation is passed the empty accumulator value passed to the foldTree function.
When folding over a non-empty tree in the Branch case, the result of the fold depends on the results for the left and right subtrees. This is done recursively, first by folding over the left subtree, then the right. For the recursive call over the left subtree, loop must build a new continuation to receive the result, this is the
(fun lacc ->
loop right (fun racc ->
cont (branchF x lacc racc))
function. What this continuation does is to make a recursive call over the right subtree, passing yet another continuation to receive the result of that fold. When that continuation is called, the results for the left and right subtrees are available in lacc and racc. At this point the accumulation function for the node can be called with the value for the current node and the results for the left and right subtrees. The result of this function is then passed to the original continuation passed to loop.
The loop function is then invoked by the foldTree function in the line:
loop t id
Here, id is the continuation which will receive the result of the fold for the root node of the tree. Since this is the value required, id just returns its argument without modification.
You might also find this description of fold for binary trees useful.