I'm getting incorrect JavaScript when using recursive functions over lists e.g.

1
2
3
4
    let rec rev_map_acc f l acc = 
        match l with
        | [] -> acc
        | h :: t -> rev_map_acc f t (f h :: acc)

when I use that with WebSharper

1
2
3
4
5
6
7
    [<SPAEntryPoint>]
    let Main() = 
        let double x = x * 2
        let result = rev_map_acc double [ 1; 3; 4 ] []
        result
        |> List.head
        |> printfn "Result: %i"

it prints Result: NaN rather than Result: 8 you get with an equivalent console application.

The generated JavaScript looks to be slightly mishandling the list splitting after the tail-call elimination:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 Client.rev_map_acc=function(f,l,acc)
 {
  var f$1,l$1;
  while(true)
   if(l.$==1)
    {
     f$1=f;
     l$1=l;
     f=f$1;
     l=l.$1;
     acc=new T({
      $:1,
      $0:f$1(l.$0),
      $1:acc
     });
    }
   else
    return acc;
 };

Zafir.4.0.159.36-beta6, works in WebSharper 3.x. Code comes from: https://github.com/fsprojects/FSharp.Compatibility/blob/master/FSharp.Compatibility.OCaml/List.fs

  • JankoA

    Thanks for the report, looking into this. The example also shows that variable copying is applied unnecessarily (having f$1=f; f=f$1;) for arguments passed around the same. WebSharper 3 does not do tail-recursion optimization for module level let rec only internal functions and with stronger conditions only.

  • github

    Great, much appreciated. We don't use this function with large lists yet but we are very pleased to see more general forms of tail-call optimisation being enabled.

  • github

    This topic has been closed.