Why tail recursive function fails for a input for which normal recursive function execute successfully? - f#

As per the MSDN documentation, while writing recursive function, The use of the accumulator argument makes the function tail recursive, which saves stack space.
I'm using two example given on the MSDN site to calculate of sum of all the numbers in a list-
first without tail recursion-
let rec Sum myList =
match myList with
| [] -> 0
| h::t -> h + Sum t
and now with tail recursion-
let Sumtail list =
let rec loop list acc =
match list with
| h::t -> loop t acc + h
| [] -> acc
loop list 0
and running both the functions with input [1..100000].
Function Sum successfully calculates the sum of this list but gives stackoverflow exception if I pass [1..1000000]
but the second function Sumtail fails at [1..100000] while it should give better performance then the first function since it uses tail recursion.
Are there any other factors which affects the recursive function?

Your second function isn't tail-recursive since loop t acc + h is parsed as (loop t acc) + h which makes + become the last operation on loop.
Change loop t acc + h to loop t (acc + h) in order that the function becomes tail-recursive.

Related

F# - Insert element in sorted list (tail-recursive)

I am trying to convert the following normal-recursive code to tail-recursive in F#, but I am failing miserably.
let rec insert elem lst =
match lst with
| [] -> [elem]
| hd::tl -> if hd > elem then
elem::lst
else
hd::(insert elem tl)
let lst1 = []
let lst2 = [1;2;3;5]
printfn "\nInserting 4 in an empty list: %A" (insert 4 lst1)
printfn "\nInserting 4 in a sorted list: %A" (insert 4 lst2)
Can you guys help? Unfortunately I am a beginner in f#. Also, can anyone point me to a good tutorial to understand tail-recursion?
The point of tail recursion is the following: the last operation before returning from a function is a call to itself; this is called a tail call, and is where tail recursion gets its name from (the recursive call is in last, i.e. tail position).
Your function is not tail recursive because at least one of its branches has an operation after the recursive call (the list cons operator).
The usual way of converting a recursive function into a tail-recursive function is to add an argument to accumulate intermediate results (the accumulator). When it comes to lists, and when you realize that the only elementary list operation is prepending an element, this also means that after you are through with processing your list, it will be reversed, and thus the resulting accumulator will usually have to be reversed again.
With all these points in mind, and given that we do not want to change the function's public interface by adding a parameter that is superfluous from the caller's point of view, we move the real work to an internal subfunction. This particular function is slightly more complicated because after the element has been inserted, there is nothing else to do but concatenate the two partial lists again, one of which is now in reverse order while the other is not. We create a second internal function to handle that part, and so the whole function looks as follows:
let insert elm lst =
let rec iter acc = function
| [] -> List.rev (elm :: acc)
| (h :: t) as ls ->
if h > elm then finish (elm :: ls) acc
else iter (h :: acc) t
and finish acc = function
| [] -> acc
| h :: t -> finish (h :: acc) t
iter [] lst
For further studying, Scott Wlaschin's F# for Fun and Profit is a great resource, and tail recursion is handled in a larger chapter about recursive types and more: https://fsharpforfunandprofit.com/posts/recursive-types-and-folds

Noob question about F# function parameter where the parameter is a list

I'm trying to play around with creating functions in F#, In the image below, I'm trying to create a function that takes a list of floats and sum the values in the list. I don't know how to pass a list as parameter in a function so I tried this to get the head of a list but the code doesn't work:
let sumlist l=
printf "%f" l.Head
Then I see some people does:
let sumlist l:float=
match l with
| [] -> 0.0
| e::li -> e + sumlist li
So is l:float the way you pass a list to a function? so like l:string would be a list of string?
But I saw list l has l.Head function to return the first element in the list(As it seems that we can't access arbitrary elements in the list like an array) but
let sumlist l:float=
printfn "%f" l.Head
gives type mismatch error.
I also don't understand the recursive code provided, I don't understand this line
| e::li -> e + sumlist li
What is ::? and Li?
Thank you for clarifying this for me!
So your first example doesn't return anything and that's because you're calling printfn which prints to the console instead of returning your types. e :: li here represents a list where e is the head and li is the rest of the list. The :: here lets the compiler know that you want to deconstruct the list.
//fully annotated
let s (l: float list) :float =
l.Head
//here the types can be inferred without any annotation
let rec sumlist l =
match l with
| [] -> 0.0
| e::li -> e + sumlist li
s [0.7]
//returns 0.7
sumlist [0.4;0.5;0.6]
//returns 1.5
In my first example if you try and remove the type annotations you'll notice that you get an error. This is because l.Head's type is ambiguous otherwise did you call l.Head on a list of strings, floats? In the sumlist function I provided you can see that I didn't need to annotate, and this is because I'm adding them up and that constrains the types.
Personally when starting I highly recommend always annotating the types. (l : float list) or (l: list<float>) is a way to say my input is a list of floats, and :float at the end how we say the return type is a float. You'll notice I put a rec keyword on our recursive function, it's better to explicitly declare whenever you make a recursive function.
Syntax questions
So is l:float the way you pass a list to a function?
No. Most of the time the compiler can figure out that you are passing a list without annotating the parameter as a list, but when it doesn't, you annotate is
l : 'a list // where 'a is generic type
// OR
l : float list // where type is specified as float
What is ::? and Li?
When pattern matching a list, [] matches to empty list, which here is used as the recursion end criteria. The other match separates head (e) from the rest of the list aka tail (li). If there is only one item in list, then li evaluates as [].
Additional note for your recursive code: You are missing the recursion keyword rec eg.
let rec sumlist ...
Recursive function implementation
The easiest way would be to use the sum function of List eg.
[0.4; 0.5; 0.6] |> List.sum // Returns 1.5
But, if you want to create this function yourself, consider using tail-recursion for better performance and to avoid stack overflow with bigger input lists.
let sumlist (values : float list) =
let rec sum (acc : float) (remaining : float list) =
match remaining with
| [] -> acc
| head :: tail -> sum (acc + head) tail
sum 0. values
Which is called
[0.4; 0.5; 0.6] |> sumlist // Returns 1.5
The difference here to a normal recursion is that each recursion calculates its own values and is not dependent on other recursions yet to come to finish its calculations.

why do continuations avoid stackoverflow?

I've been trying to understand continuations / CPS and from what I can gather it builds up a delayed computation, once we get to the end of the list we invoke the final computation.
What I don't understand is why CPS prevents stackoverflow when it seems analogous to building up a nested function as per the naive approach in Example 1. Sorry for the long post but tried to show the idea (and possibly where it goes wrong) from basics:
So:
let list1 = [1;2;3]
Example 1: "Naive approach"
let rec sumList = function
|[] -> 0
|h::t -> h + sumList t
So when this runs, iteratively it results in:
1 + sumList [2;3]
1 + (2 + sumList [3])
1 + (2 + (3 + 0))
So the nesting (and overflow issues) can be overcome by Tail Recursion - running an accumulator i.e.
"Example 2: Tail Recursion"
let sumListACC lst =
let rec loop l acc =
match l with
|[] -> acc
|h::t -> loop t (h + acc)
loop lst 0
i.e,
sumList[2;3] (1+0)
sumList[3] (2+1)
sumList[] (3+3)
So because the accumulator is evaluated at each step, there is no nesting and we avoid bursting the stack. Clear!
Next comes CPS, I understand this is required when we already have an accumulator but the function is not tail recursive e.g. with Foldback. Although not required in the above example, applying CPS to this problem gives:
"Example 3: CPS"
let sumListCPS lst =
let rec loop l cont =
match l with
|[] -> cont 0
|h::t -> loop t (fun x -> cont( h + x))
loop lst (fun x -> x)
To my understanding, iteratively this could be written as:
loop[2;3] (fun x -> cont (1+x))
loop[3] (fun x ->cont (1+x) -> cont(2+x))
loop[] (fun x -> cont (1+x) -> cont(2+x) -> cont (3+x)
which then reduces sequentially from the right with the final x = 0 i.e:
cont(1+x)-> cont(2+x) -> cont (3+0)
cont(1+x)-> cont(2+x) -> 3
cont(1+x) -> cont (2+3)
...
cont (1+5) -> 6
which I suppose is analogous to:
cont(1+cont(2+cont(3+0)))
(1+(2+(3+0)))
correction to original post - realised that it is evaluated from the right, as for example replacing cont(h +x) with cont(h+2*x) yields 17 for the above example consistent with: (1+2*(2+2*(3+2*0)))
i.e. exactly where we started in example 1, based on this since we still need to keep track of where we came from why does using it prevent the overflow issue that example 1 suffers from?
As I know it doesn't, where have I gone wrong?
I've read the following posts (multiple times) but the above confusion remains.
http://www.markhneedham.com/blog/2009/06/22/f-continuation-passing-style/
http://codebetter.com/matthewpodwysocki/2008/08/13/recursing-on-recursion-continuation-passing/
http://lorgonblog.wordpress.com/2008/04/05/catamorphisms-part-one/
What happens is quite simple.
.NET (and other platforms, but we're discussing F# right now) stores information in two locations: the stack (for value types, for pointer to objects, and for keeping track of function calls) and the heap (for objects).
In regular non-tail recursion, you keep track of your progress in the stack (quite obviously). In CPS, you keep track of your progress in lambda functions (which are on the heap!), and tail recursion optimization makes sure that the stack stays clear of any tracking.
As the heap is significantly larger than the stack, it is (in some cases) better to move the tracking from the stack to the heap - via CPS.

Using continuation to transform binary recursion to tail recursion

As I'm reading the Programming F# book, I found the example code snippet on page 195 as follows:
type ContinuationStep<'a> =
| Finished
| Step of 'a * (unit -> ContinuationStep<'a>)
let iter f binTree =
let rec linearize binTree cont =
match binTree with
| Empty -> cont()
| Node(x, l, r) ->
Step(x, (fun () -> linearize l (fun() -> linearize r cont)))
let steps = linearize binTree (fun () -> Finished)
let rec processSteps step =
match step with
| Finished -> ()
| Step(x, getNext)
-> f x
processSteps (getNext())
processSteps steps
By using continuation, the binary recursion of traversing a binary has been transformed to tail-recursive function processSteps. My question is that the other function, linearize seems to be non-tail-recursive. Does that mean we are not able to transform a binary-recursion to a tail-recursion completely even using continuation?
linearize is tail-recursive: you don't need to come back from the recursive call to continue the computation.
fun () -> linearize l (fun() -> linearize r cont)
doesn't call linearize. The computation is suspended until processSteps calls getNext ().
The example is a bit subtle because it does not use ordinary continuations, but instead builds a structure that can be evaluated step-by-step. In a place where you would normally make a recursive call, it returns a value Step that contains the function that you'd (recursively) call.
In the second case, the linearize function returns a Step containing a function that will call linearize recursively, but it does not immediately make the recursive call. So the function does not make a recursive call (it just stores a recursive reference).
It only makes sense to consider whether the program is tail-recursive when you look at processSteps, because that does the actual looping - and that is tail-recursive, because it runs a Step by Step without keeping stack space for each Step.
If you wanted to construct a list instead of a chain of lazy steps then you'd have to make the recursive call to linearize immediately inside the continuation:
let rec linearize binTree cont =
match binTree with
| Empty -> cont []
| Node(x, l, r) ->
linearize l (fun l -> linearize r (fun v -> cont (x::v)))
This is essentially the same as the previous function, but it actually calls linearize instead of building Step containing a function that will call linearize.

Conversion to tail recursion

Hey guys, I'm trying to get cozy with functional programming (particularly with F#), and I've hit a wall when it comes to building tail-recursive functions. I'm pretty good with turning basic recursion (where the function basically calls itself once per invocation), into tail recursion, but I now have a slightly more complicated situation.
In my case, the function must accept a single list as a parameter. When the function is called, I have to remove the first element from the list, and then recur using the remainder of the list. Then I need to apply the first element which I removed in some way to the result of the recursion. Next, I remove the second element and do the same thing (Note: when I say "remove the seond element", that is from the original list, so the list passed at the recursion includes the first element as well). I do the same for the third, fourth, etc. elements of the list.
Is there a way to convert the above situation into a tail-recursive function? Maybe nested tail-recursive functions??? Thank you for any answers.
Okay, so here's my basic code. This particular one is a permutation generator (I'm not too concern with the permutation part, though - it's the recursion I'd like to focusing on):
let permutationsOther str =
match str with
| value :: [] ->
[[value]]
| _ ->
let list = (List.map (fun a -> // This applies the remove part for every element a
let lst = (List.filter (fun b -> b <> a) str) // This part removes element a from the list
let permutedLst = permutations lst // recursive call
consToAll a permutedLst // constToAll this is my own function which performs "cons" operation with a and every element in the list permutedLst
) str)
List.reduce (fun acc elem -> elem # acc) list // flatten list of lists produce by map into a single list
I hope this is clear enough - I'll be happy to provide clarifications if needed.
By the way, I have found just a way to rewrite this particular function so that it only uses a single recursion, but it was a fluke more than an informed decision. However, this has encouraged me that there may be a general method of turning multiple recursion into single recursion, but I have not yet found it.
Conversion to CPS should do the trick:
NOTE 1: Source of the sample is typed directly in browser, so may contain errors :(. But I hope it can demonstrate the general idea.
NOTE 2: consToAll function should be converted to CPS too: consToAll: 'T -> 'T list list -> ('T list list -> 'R) -> 'R
let remove x l = List.filter ((<>) x) l // from original post: should duplicates also be removed ???
let permute l =
let rec loop k l =
match l with
| [] -> k []
| [value] -> k [[value]]
| _ -> filter l [] l (fun r -> r |> List.reduce (fun acc elem -> elem # acc) |> k )
and filter l acc orig fk =
match l with
| [] -> fk acc
| x::xs ->
remove x orig
|> loop (fun res ->
consToAll x res (fun rs -> filter xs (rs::acc) orig fk)
)
loop id l

Resources