This question uses the following "lazy list" (aka "stream") type:
type 'a lazylist = Cons of 'a * (unit -> 'a lazylist)
My question is: how to define a tail-recursive function lcycle
that takes a non-empty (and non-lazy) list l
as argument, and returns the lazylist
corresponding to repeatedly cycling over the elements l
. For example:
# ltake (lcycle [1; 2; 3]) 10;;
- : int list = [1; 2; 3; 1; 2; 3; 1; 2; 3; 1]
(ltake
is a lazy analogue of List::take
; I give one implementation at the end of this post.)
I have implemented several non-tail-recursive versions of lcycles
, such as:
let lcycle l =
let rec inner l' =
match l' with
| [] -> raise (Invalid_argument "lcycle: empty list")
| [h] -> Cons (h, fun () -> inner l)
| h::t -> Cons (h, fun () -> inner t)
in inner l
...but I have not managed to write a tail-recursive one.
Basically, I'm running into the problem that lazy evaluation is implemented by constructs of the form
Cons (a, fun () -> <lazylist>)
This means that all my recursive calls happen within such a construct, which is incompatible with tail recursion.
Assuming the lazylist
type as defined above, is it possible to define a tail-recursive lcycle
? Or is this inherently impossible with OCaml?
EDIT: My motivation here is not to "fix" my implementation of lcycle
by making it tail-recursive, but rather to find out whether it is even possible to implement a tail recursive version of lcycle
, given the definition of lazylist
above. Therefore, pointing out that my lcycle
is fine misses what I'm trying to get at. I'm sorry I did not make this point sufficiently clear in my original post.
This implementation of ltake
, as well as the definition of the lazylist
type above, comes from here:
let rec ltake (Cons (h, tf)) n =
match n with
0 -> []
| _ -> h :: ltake (tf ()) (n - 1)