type Thunk<'a> = T of (unit -> 'a)
let eval (T x) = x ()
let apply f (x : Thunk<'a>) = T (fun _ -> (eval f) x)
let one = T (fun _ -> 1)
let two = T (fun _ -> 2)
let add = T (fun _ x y -> eval x + eval y)
let three = apply (apply add one) two
printfn "%A" (eval three)
type TList<'a> =
| Nil
| Cons of Thunk<'a> * Thunk<TList<'a>>
let nil = T (fun _ -> Nil)
let cons = T (fun _ x xs -> Cons (x, xs))
let zero = T (fun _ -> 0)
let list1 = apply (apply cons zero) nil
printfn "%A" (eval list1)
let rec inf1 = T (fun _ -> Cons (zero, inf1))
printfn "%A" (eval inf1)
let rec map = T (fun _ f list ->
match eval list with
| Cons (x, xs) -> Cons ((apply f x), (apply (apply map f) xs))
| Nil -> Nil)
let rec take = T (fun _ n list ->
match eval list with
| Cons (x, xs) -> let n' = eval n
if n' <= 0
then Nil
else Cons (x, apply (apply take (T (fun _ -> n' - 1))) xs)
| Nil -> Nil)
let addOne = apply add one
let rec inf2 = T (fun _ -> Cons (zero, apply (apply map addOne) inf2))
let twenty = T (fun _ -> 20)
let list2 = apply (apply take twenty) inf2
let rec evalList list =
match eval list with
| Cons (x, xs) -> (eval x) :: (evalList xs)
| Nil -> []
printfn "%A" (evalList list2)