File: assume_no_perform.ml

package info (click to toggle)
js-of-ocaml 6.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 37,932 kB
  • sloc: ml: 135,957; javascript: 58,364; ansic: 437; makefile: 422; sh: 12; perl: 4
file content (153 lines) | stat: -rw-r--r-- 3,954 bytes parent folder | download
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
open Printf
open Effect
open Effect.Deep

module type TREE = sig
  type 'a t
  (** The type of tree. *)

  val deep : int -> int t
  (** [deep n] constructs a tree of depth n, in linear time, where every node at
      level [l] has value [l]. *)

  val to_iter : 'a t -> ('a -> unit) -> unit
  (** Iterator function. *)

  val to_gen : 'a t -> unit -> 'a option
  (** Generator function. [to_gen t] returns a generator function [g] for the
      tree that traverses the tree in depth-first fashion, returning [Some x]
      for each node when [g] is invoked. [g] returns [None] once the traversal
      is complete. *)

  val to_gen_cps : 'a t -> unit -> 'a option
  (** CPS version of the generator function. *)
end

module Tree : TREE = struct
  type 'a t =
    | Leaf
    | Node of 'a t * 'a * 'a t

  let rec deep = function
    | 0 -> Leaf
    | n ->
        let t = deep (n - 1) in
        Node (t, n, t)

  let rec iter f = function
    | Leaf -> ()
    | Node (l, x, r) ->
        iter f l;
        f x;
        iter f r

  (* val to_iter : 'a t -> ('a -> unit) -> unit *)
  let to_iter t f = iter f t

  (* val to_gen : 'a t -> (unit -> 'a option) *)
  let to_gen (type a) (t : a t) =
    let module M = struct
      type _ Effect.t += Next : a -> unit Effect.t
    end in
    let open M in
    let rec step =
      ref (fun () ->
          try_with
            (fun t ->
              iter (fun x -> perform (Next x)) t;
              None)
            t
            { effc =
                (fun (type a) (e : a Effect.t) ->
                  match e with
                  | Next v ->
                      Some
                        (fun (k : (a, _) continuation) ->
                          (step := fun () -> continue k ());
                          Some v)
                  | _ -> None)
            })
    in
    fun () -> !step ()

  let to_gen_cps t =
    let next = ref t in
    let cont = ref Leaf in
    let rec iter t k =
      match t with
      | Leaf -> run k
      | Node (left, x, right) -> iter left (Node (k, x, right))
    and run = function
      | Leaf -> None
      | Node (k, x, right) ->
          next := right;
          cont := k;
          Some x
    in
    fun () -> iter !next !cont
end

let get_mean_sd l =
  let get_mean l =
    List.fold_right (fun a v -> a +. v) l 0. /. (float_of_int @@ List.length l)
  in
  let mean = get_mean l in
  let sd = get_mean @@ List.map (fun v -> abs_float (v -. mean) ** 2.) l in
  mean, sd

let benchmark f n =
  let rec run acc = function
    | 0 -> acc
    | n ->
        let t1 = Sys.time () in
        let () = f () in
        let d = Sys.time () -. t1 in
        run (d :: acc) (n - 1)
  in
  let r = run [] n in
  get_mean_sd r

(* Main follows *)

type _ Effect.t += Dummy : unit t [@@warning "-38"]

let () =
  try_with
    (fun () ->
      let n = try int_of_string Sys.argv.(1) with _ -> 21 in
      let t = Tree.deep n in
      let iter_fun () = Tree.to_iter t (fun _ -> ()) in
      let rec consume_all f =
        match f () with
        | None -> ()
        | Some _ -> consume_all f
      in

      (* The code below should be called in direct style despite the installed
         effect handler *)
      Jsoo_runtime.Effect.assume_no_perform (fun () ->
          let m, sd = benchmark iter_fun 5 in
          let () = printf "Iter: mean = %f, sd = %f\n%!" m sd in

          let gen_cps_fun () =
            let f = Tree.to_gen_cps t in
            consume_all f
          in

          let m, sd = benchmark gen_cps_fun 5 in
          printf "Gen_cps: mean = %f, sd = %f\n%!" m sd);

      let gen_fun () =
        let f = Tree.to_gen t in
        consume_all f
      in

      let m, sd = benchmark gen_fun 5 in
      printf "Gen_eff: mean = %f, sd = %f\n%!" m sd)
    ()
    { effc =
        (fun (type a) (e : a Effect.t) ->
          match e with
          | Dummy -> Some (fun (k : (a, _) continuation) -> continue k ())
          | _ -> None)
    }