File: tailcall.wiki

package info (click to toggle)
js-of-ocaml 5.9.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 32,020 kB
  • sloc: ml: 91,250; javascript: 57,289; ansic: 315; makefile: 271; lisp: 23; sh: 6; perl: 4
file content (99 lines) | stat: -rw-r--r-- 2,252 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
= Tail call optimization
JavaScript does not (yet) support tail call optimization.
To circumvent this limitation, and mitigate stack overflows, the Js_of_ocaml
compiler optimizes some common tail call patterns.
Besides, all tail calls are optimized when you set the flag
{{{--enable=effects}}}, at the cost of some performance degradation.

=== Self tail recursive
Self tail recursive function are compiled into a loop.

==== OCaml
<<code language="ocaml"|
let rec fact x acc =
  if x = 0
  then acc
  else fact (pred x) (acc * x)
>>

==== JavaScript
<<code language="javascript"|
function fact(x,acc){
  var x$0=x,acc$0=acc;
  for(;;){
    if(0===x$0) return acc$0;
    var acc$1=caml_mul(acc$0,x$0),
        x$1=x$0-1|0,
        x$0=x$1,
        acc$0=acc$1;
    continue
  }
}
>>


=== Mutually tail recursive functions
Mutually tail recursive functions are compiled using a trampoline.
Note that the generated code does not return to the trampoline at every
recursive call to prevent too much slow down.

==== OCaml
<<code language="ocaml"|
let rec even n =
  match n with
  | 0 -> true
  | x -> odd (x-1)
and odd n =
  match n with
  | 0 -> false
  | x -> even (x-1);;
>>

==== JavaScript
<<code language="javascript"|
function even$0(counter,n){
  if(0===n)return 1;
  var _e_=n-1|0;
  if(counter<50){
    var counter$0=counter+1|0;
    return odd$0(counter$0,_e_)
  }
  return caml_trampoline_return(odd$0,[0,_e_])
}
function odd$0(counter,n){
  if(0===n)return 0;
  var _d_=n-1|0;
  if(counter<50){
    var counter$0=counter+1|0;
    return even$0(counter$0,_d_)
  }
  return caml_trampoline_return(even$0,[0,_d_])
}
function even(n){return caml_trampoline(even$0(0,n))}
function odd(n){return caml_trampoline(odd$0(0,n))}
>>


== Examples of pattern not optimized

Recursive function where the tail call is made inside an intermediate function.
<<code language="ocaml"|
let rec f x =
  let g delta = f (x - delta) in
  if x < 0 then 0
  else if x mod 2 = 0
  then g 2
  else g 1;;
>>

Tail call of a function given as argument
<<code language="ocaml"|
let bind x f =
  match x with
  | None -> None
  | Some x -> f x
>>

Note that in the future, more tail call optimizations could be perform with function specialization and
better inlining.