The example is a bit subtle because it does not use regular extensions, but instead builds a structure that can be evaluated step by step. In the place where you usually make a recursive call, it returns a Step value that contains the function that you (recursively) call.
In the second case, the linearize function returns Step , containing a function that will call linearize recursively, but not immediately make a recursive call. Thus, the function does not make a recursive call (it just stores a recursive link).
It only makes sense to think about whether the program is tail-recursive when you look at processSteps because it makes the actual loop - and it is tail-recursive as it executes Step by Step without saving stack space for each Step .
If you want to build a list instead of a chain of lazy steps, you will need to make a linearize recursive call right 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 actually calls linearize instead of building a Step containing a function that will call linearize .
source share