Code Snippet:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| type 'a ListLazy = Cons of 'a * 'a ListLazy Lazy | Nil
module List =
module Lazy =
let single h = Cons(h, lazy (Nil))
let cons h l = Cons(h, lazy (l))
let head = function | Nil -> failwith "empty list" | Cons(h,_) -> h
let tail = function | Nil -> failwith "empty list" | Cons(_,t) -> t.Force()
let rec iter f = function
| Nil -> () | Cons(h,t) -> f h; iter f (t.Force())
let rec map f = function
| Nil -> Nil | Cons(h,t) -> Cons(f h, lazy (map f (t.Force())))
let rec fold f init = function
| Nil -> init | Cons(h,t) -> fold f (f init h) (t.Force())
let rec foldBack f init = function
| Nil -> init | Cons(h,t) -> f h (lazy (foldBack f init (t.Force())))
let rec unfold f init = f init |> function
| None -> Nil | Some(a,s) -> Cons (a, lazy (unfold f s))
let rec reduce f = function
| Nil -> failwith "empty list" | Cons(h,t) -> fold f h (t.Force())
let rec reduceBack f = function
| Nil -> failwith "empty list" | Cons(h,t) -> foldBack f h (t.Force())
let rec skip n = function
| Nil -> Nil | Cons(h,t) -> (n = 0I) |> function
| true -> cons h (t.Force())
| false -> skip (n-1I) (t.Force())
let rec take n = function
| Nil -> Nil | Cons(h,t) -> (n = 0I) |> function
| true -> Nil
| false -> Cons(h, lazy (take (n-1I) (t.Force())))
let rec append l1 l2 = l1 |> function
| Nil -> l2 | Cons(h,t) -> Cons(h, lazy (append (t.Force()) l2))
let rec concat = function
| Nil -> Nil | Cons(h,t) -> append h (concat (t.Force()))
let rec ofList = function
| [] -> Nil | h :: t -> cons h (ofList t)
let toList l =
let rec toList' acc = function
| Nil -> List.rev acc
| Cons(h,t) -> toList' (h::acc) (t.Force())
toList' [] l
|
Code output:
Infinite Fibonacci (and squared) sequence
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| let fib =
(List.Lazy.single 0I,
List.Lazy.unfold(fun (a1,a2) -> Some(a1+a2,(a2,a1+a2))) (1I,0I))
||> List.Lazy.append
let fibSquared =
fib |> List.Lazy.foldBack(fun x l -> Cons(x*x,l)) Nil
fib
|> List.Lazy.take 10I
|> List.Lazy.iter(printf "%A ")
fibSquared
|> List.Lazy.take 10I
|> List.Lazy.iter(printf "%A ")
|
Runtime errors when skipping/taking on empty sequences (F# Seq)
1
2
3
4
5
6
| fib
|> List.Lazy.take 10I
|> List.Lazy.toList
|> List.toSeq
|> Seq.skip 20
|> Seq.iter(printf "%A ")
|
1
2
3
4
5
6
| fib
|> List.Lazy.take 10I
|> List.Lazy.toList
|> List.toSeq
|> Seq.take 20
|> Seq.iter(printf "%A ")
|
No runtime errors when skipping/taking on empty lists
1
2
3
4
5
6
7
8
9
| fib
|> List.Lazy.take 10I
|> List.Lazy.skip 20I // Behave as C# Linq.Enumerable.Skip
|> List.Lazy.iter(printf "%A ")
fib
|> List.Lazy.take 10I
|> List.Lazy.take 20I // Behave as C# Linq.Enumerable.Take (or F# Seq.truncate)
|> List.Lazy.iter(printf "%A ")
|
References: