File: test_map_traversal.ml

package info (click to toggle)
janest-base 0.17.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,632 kB
  • sloc: ml: 48,653; ansic: 281; javascript: 126; makefile: 14
file content (156 lines) | stat: -rw-r--r-- 4,102 bytes parent folder | download | duplicates (2)
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
open! Import
open! Map
open! Int

module Lazy_apply = struct
  module T = struct
    type 'a t = { compute : unit -> 'a } [@@unboxed]

    let run t = t.compute ()
    let return x = { compute = (fun () -> x) }
    let map x ~f = { compute = (fun () -> f (run x)) }
    let both x y = { compute = (fun () -> run x, run y) }
    let map2 a b ~f = map (both a b) ~f:(fun (x, y) -> f x y)
    let map = `Custom map
  end

  include T
  include Applicative.Make_using_map2 (T)

  let of_thunk f = { compute = (fun () -> run (f ())) }
end

module Lazy_map = Map.Make_applicative_traversals (Lazy_apply)

let%expect_test "mapi correctness check" =
  let map = Map.of_alist_exn (module Int) (List.init 100 ~f:(fun x -> x, x)) in
  let f ~key:_ ~data = data + 1 in
  let test_output =
    Lazy_map.mapi map ~f:(fun ~key ~data -> Lazy_apply.return (f ~key ~data))
    |> Lazy_apply.run
  in
  let reference_output = Map.mapi map ~f in
  require [%here] (Map.equal Int.equal test_output reference_output);
  require [%here] (Map.invariants test_output);
  [%expect {| |}]
;;

let%expect_test "filter_mapi correctness check" =
  let map = Map.of_alist_exn (module Int) (List.init 1000 ~f:(fun x -> x, x)) in
  let f ~key:_ ~data = if data % 50 > 10 then None else Some data in
  let test_output =
    Lazy_map.filter_mapi map ~f:(fun ~key ~data -> Lazy_apply.return (f ~key ~data))
    |> Lazy_apply.run
  in
  let reference_output = Map.filter_mapi map ~f in
  require [%here] (Map.equal Int.equal test_output reference_output);
  require [%here] (Map.invariants test_output);
  [%expect {| |}]
;;

module Step_applicative = struct
  module M = struct
    type 'a t = { compute : steps:int -> ('a * int, 'a t) Either.t }

    let return x = { compute = (fun ~steps -> First (x, steps)) }

    let step x =
      let rec t =
        { compute = (fun ~steps -> if steps > 0 then First (x, steps - 1) else Second t) }
      in
      t
    ;;

    let internal_map x ~f =
      let rec fn t =
        { compute =
            (fun ~steps ->
              match t.compute ~steps with
              | First (x, steps) -> First (f x, steps)
              | Second t -> Second (fn t))
        }
      in
      fn x
    ;;

    let map2 a b ~f =
      let rec fn a =
        { compute =
            (fun ~steps ->
              match a.compute ~steps with
              | First (x, steps) -> (internal_map b ~f:(fun y -> f x y)).compute ~steps
              | Second t -> Second (fn t))
        }
      in
      fn a
    ;;

    let map = `Custom internal_map

    let of_thunk f =
      { compute =
          (fun ~steps ->
            let t = f () in
            t.compute ~steps)
      }
    ;;
  end

  include M
  include Applicative.Make_using_map2 (M)
end

module Step_map = Map.Make_applicative_traversals (Step_applicative)

let%expect_test "mapi lazy check" =
  let map = Map.of_alist_exn (module Int) (List.init 10 ~f:(fun x -> x, x)) in
  let f ~key:_ ~data = data * 2 in
  (* transform the map, expect no output yet *)
  let step_computation =
    Step_map.mapi map ~f:(fun ~key ~data ->
      Step_applicative.of_thunk (fun () ->
        print_s [%message (key : int) (data : int)];
        Step_applicative.step (f ~key ~data)))
  in
  [%expect {| |}];
  (* take a few steps, expect some but not all output *)
  let more_computation =
    match step_computation.compute ~steps:3 with
    | First _ -> assert false
    | Second c -> c
  in
  [%expect
    {|
    ((key  0)
     (data 0))
    ((key  1)
     (data 1))
    ((key  2)
     (data 2))
    ((key  3)
     (data 3))
    |}];
  (* take more than enough steps to finish, expect the rest of the output *)
  let test_output =
    match more_computation.compute ~steps:100 with
    | First (r, _) -> r
    | Second _ -> assert false
  in
  let reference_output = Map.mapi map ~f in
  require [%here] (Map.equal Int.equal test_output reference_output);
  [%expect
    {|
    ((key  4)
     (data 4))
    ((key  5)
     (data 5))
    ((key  6)
     (data 6))
    ((key  7)
     (data 7))
    ((key  8)
     (data 8))
    ((key  9)
     (data 9))
    |}]
;;