[Mono-list] Tail calls

mono user monouser22 at gmail.com
Sun Sep 15 12:54:32 UTC 2013


I wondered if it would be possible to have some advice on how tail
recursion elimination works in Mono. I would like to understand under
what circumstances Mono can do a tail recursive call without leaving
the caller on the stack, and when it cannot. I am afraid I could not
find this information anywhere, though I did not try reading the
sources. Many thanks in advance.

I have a large F# project that I want to run under Mono, and was
pleased to see that all 1500+ unit tests passed the first time under
3.2.1. However, my code runs out of stack once applied to non-trivial
input, even when I allocate a gigabyte of stack.

Here is a cut-down example that started its life as a much larger fold
(which would be prohibitively expensive to rewrite in imperative
style). Under .net it runs to completion, whereas under Mono it dies
after i reaches 17. Is there a way of rewriting the map so that it
would not leave anything on the stack when evaluating f?

[I cannot just use List.map because it stays on the stack while
applying f, and so would cause an overflow e.g. if given a function
that uses the same call to map again over and over as it descends down
a data structure.]

fsharpc --tailcalls+ tailtest.fs
mono --optimize=tailc tailtest.exe

   let rec mapk f xs k =
       match xs with
         [] -> k []
       | x::xs -> mapk f xs (fun xs' -> f x (fun x' -> (x' :: xs') |> k))

   let test_tail n =
       printf "Testing depth %u\n" n
       let xs = [1..n]
       let expected = List.map (fun x -> x + 1) xs
       let actual = mapk (fun x k -> k (x + 1)) xs id
       if expected <> actual then
           failwithf "Something went badly wrong"

   for i=0 to 25 do
       test_tail (1<<<i)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ximian.com/pipermail/mono-list/attachments/20130915/b9a36f66/attachment.html>


More information about the Mono-list mailing list