## What gets optimized

Pattern | Optimization
Self-recursive tail calls | Compiled to a loop
Mutually recursive tail calls | Compiled with a trampoline
Other tail calls | Not optimized (may overflow)

To optimize other tail calls, try `--effects=cps` or `--effects=double-translation`. This partially transforms the code to continuation-passing style, but has a performance cost. See effect handlers.

## Self-recursive functions

Self-recursive tail calls are compiled into loops:

    let rec fact x acc =
      if x = 0
      then acc
      else fact (pred x) (acc * x)

Generated JavaScript:

    function fact(x$1, acc$1){
      var x = x$1, acc = acc$1;
      for(;;){
        if(0 === x) return acc;
        var acc$0 = runtime.caml_mul(acc, x), x$0 = x - 1 | 0;
        x = x$0;
        acc = acc$0;
      }
    }

## Mutually recursive functions

Mutually recursive functions use a trampoline—a loop that catches returned continuations and re-invokes them, avoiding deep call stacks:

    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)

Generated JavaScript:

    function even$0(counter, n){
      if(0 === n) return 1;
      var a = n - 1 | 0;
      if(counter >= 50) return caml_trampoline_return(odd$0, [0, a]);
      var counter$0 = counter + 1 | 0;
      return odd$0(counter$0, a);
    }
    function even(n){return caml_trampoline(even$0(0, n));}
    function odd$0(counter, n){
      if(0 === n) return 0;
      var a = n - 1 | 0;
      if(counter >= 50) return caml_trampoline_return(even$0, [0, a]);
      var counter$0 = counter + 1 | 0;
      return even$0(counter$0, a);
    }
    function odd(n){return caml_trampoline(odd$0(0, n));}

Note: The generated code doesn't return to the trampoline on every call (controlled by the `tc_depth` parameter, default 50). This balances stack safety with performance.

## Patterns not optimized

These patterns are not optimized and may cause stack overflows with deep recursion:

Tail call through a local function:

    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 to a function argument:

    let bind x f =
      match x with
      | None -> None
      | Some x -> f x  (* f is unknown, can't optimize *)

For these patterns, you can try `--effects=cps`.

## Tuning

The trampoline depth can be adjusted with `--set tc_depth=N` (default: 50). Higher values improve performance but increase stack usage.

## See also

- Effect handlers — Full tail call optimization with CPS
- Command-line options — The `tc_depth` parameter