Source file fast_sequence.ml

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
open! Core

type 'a t =
  | Empty : 'a t
  | Return : 'a -> 'a t
  | List : 'a list -> 'a t
  | List_map : 'a list * ('a -> 'b) -> 'b t
  | Cons : 'a * 'a t Lazy.t -> 'a t
  | Concat : 'a t list -> 'a t
  | Map : 'a t * ('a -> 'b) -> 'b t
  | Bind : 'a t * ('a -> 'b t) -> 'b t
  | Recurse :
      { init : 'acc
      ; f : 'acc -> [ `Finish of 'a | `Continue of 'acc ] t
      }
      -> 'a t
  | Lazy : 'a t Lazy.t -> 'a t
[@@deriving sexp_of]

let bind t ~f =
  match t with
  | Empty -> Empty
  | Return x -> f x
  | t -> Bind (t, f)
;;

let rec next : type a. a t -> (a * a t) option = function
  | Empty -> None
  | Return x -> Some (x, Empty)
  | List [] -> None
  | List (x :: xs) -> Some (x, List xs)
  | List_map ([], _) -> None
  | List_map (x :: xs, f) -> Some (f x, List_map (xs, f))
  | Cons (x, t) -> Some (x, Lazy t)
  | Concat [] -> None
  | Concat (t :: ts) ->
    (match next t with
     | None -> next (Concat ts)
     | Some (v, t) -> Some (v, Concat (t :: ts)))
  | Map (t, f) ->
    (match next t with
     | None -> None
     | Some (v, t) -> Some (f v, Map (t, f)))
  | Bind (t, f) ->
    (match next t with
     | None -> None
     | Some (v, t) -> next (Concat [ f v; Bind (t, f) ]))
  | Recurse { init; f } ->
    bind (f init) ~f:(function
      | `Finish x -> Return x
      | `Continue acc -> Recurse { init = acc; f })
    |> next
  | Lazy t -> next (force t)
;;

let empty = Empty

let of_list = function
  | [] -> Empty
  | [ x ] -> Return x
  | xs -> List xs
;;

let of_list_map xs ~f =
  match xs with
  | [] -> Empty
  | [ x ] -> Return (f x)
  | xs -> List_map (xs, f)
;;

let concat ts = Concat ts
let return x = Return x
let map t ~f = Map (t, f)
let recurse ~init ~f = Recurse { init; f }
let cons x t = Cons (x, t)

let cache t =
  let rec aux t =
    lazy
      (match next t with
       | None -> Empty
       | Some (v, t) -> Cons (v, aux t))
  in
  Lazy (aux t)
;;