type nat = Zero | S of nat;;


let rec zipwith_l f xs ys =
  lazy (match Lazy.force xs with
	| [] -> []
	| x::xs' ->
	   match Lazy.force ys with
	   | [] -> []
	   | y::ys' -> f x y :: zipwith_l f xs' ys')
;;

let rec plus x y =
  match x with
  | Zero -> y
  | S(x') -> S(plus x' y)
;;

let tail_l xs =
  match Lazy.force xs with
  | [] -> Error_empty_list
  | x::xs' -> xs'
;;

let rec nth_l n xs =
  match Lazy.force xs with
  | [] -> Error_nth_l
  | x::xs' ->
     match n with
     | Zero -> x
     | S(n') -> nth_l n' xs'
;;

let fix f =
  let rec x = lazy (Lazy.force (f x))
  in x
;;

let rec take_l n xs =
  match Lazy.force xs with
  | [] -> []
  | x::xs' ->
     match n with
     | Zero -> []
     | S(n') -> x::take_l n' xs'
;;

let rec fibs = lazy (Zero :: lazy (S(Zero) :: zipwith_l plus fibs (tail_l fibs)))
;;

let main n = take_l n fibs;;