{OCaml] 頭の悪い無限リスト

Haskellのようなやつ。書いて書けないことはなかった。面倒ですが。

type 'a item = E | S of ('a * ('a inflist))
and 'a inflist = 'a item lazy_t;;

let rec take : int -> 'a inflist -> 'a inflist = fun n list ->
  if n = 0 then lazy E else
  match Lazy.force list with
  | E -> lazy E
  | S (x, xs) -> lazy (S (x, take (n - 1) xs));;

let rec print_inflist : ('a -> unit) -> 'a inflist -> unit = fun print list ->
  match Lazy.force list with
  | E -> ()
  | S (x, xs) -> print x; print_inflist print xs;;

let rec progression : int -> int -> int inflist = fun step start ->
  lazy (S (start, progression step (start + step)));;

print_inflist (fun x -> print_int x; print_newline ()) (take 10 (progression 1 1));;

let from_inflist : 'a inflist -> 'a Stream.t = fun list ->
  let top = ref list in
  Stream.from (fun _ -> 
    match Lazy.force !top with
    | E -> None
    | S (x, xs) -> top := xs; Some x);;

let s = from_inflist (progression 1 1) in
let i = ref (Stream.npeek 10 s) in
while !i <> [] do
  match !i with
  | [] -> failwith "END";
  | x :: xs -> print_int x; print_newline (); i := xs
done;;

何が面倒ってlazy (S (x, y))を演算子に閉じ込めてx ^:: yなんて書きたいと思ってもそうするとlazyではなくなるため目的を達成できなくなるため毎回lazy (S (x, y))って書かないといけないところです。