Skip to content

Commit

Permalink
basic traversal functions for Lazy: map, iter, fold, equal
Browse files Browse the repository at this point in the history
  • Loading branch information
gasche committed Dec 29, 2020
1 parent 9f53c6b commit f51899f
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 5 deletions.
3 changes: 3 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ Working version
- #9582: Add Array.{find_opt,find_map,split,combine}.
(Nicolás Ojeda Bär, review by Daniel Bünzli and Gabriel Scherer)

- #????: basic generic functions for Lazy: map, iter, fold, equal
(Gabriel Scherer, review by ????)

### Other libraries:

* #10084: Unix.open_process_args* functions now look up the program in the PATH.
Expand Down
15 changes: 15 additions & 0 deletions stdlib/lazy.ml
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,18 @@ let lazy_from_fun = from_fun
let lazy_from_val = from_val

let lazy_is_val = is_val


let map f x =
lazy (f (force x))

let iter f x =
f (force x)

let fold f x acc =
f (force x) acc

let equal eq x y =
let vx = force x in
let vy = force y in
eq vx vy
34 changes: 29 additions & 5 deletions stdlib/lazy.mli
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type 'a t = 'a CamlinternalLazy.t
are rejected by the type-checker.
*)

(** {1 Basic primitives} *)

exception Undefined

Expand All @@ -67,6 +68,34 @@ external force : 'a t -> 'a = "%lazy_force"
recursively.
*)

val is_val : 'a t -> bool
(** [is_val x] returns [true] if [x] has already been forced and
did not raise an exception.
@since 4.00.0 *)

(** {1 Generic traversal functions} *)

val map : ('a -> 'b) -> 'a t -> 'b t
(** [map f x] returns a suspension that, when forced,
forces [x] and applies [f] to its value. *)

val iter : ('a -> unit) -> 'a t -> unit
(** [iter f x] forces the suspension [x] and applies [f] to its value. *)

val fold : ('a -> 'b -> 'b) -> 'a t -> 'b -> 'b
(** [fold f x acc] forces the suspension [x] to a value [v],
and returns [f v acc]. *)

val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
(** [equal eq x y] checks if the suspensions [x] and [y]
have equal values according to the equality predicate [eq]. *)


(** {1 Advanced}
The following definitions are for advanced uses only; they require
familiary with the lazy compilation scheme to be used correctly. *)

val force_val : 'a t -> 'a
(** [force_val x] forces the suspension [x] and returns its
result. If [x] has already been forced, [force_val x]
Expand All @@ -93,11 +122,6 @@ val from_val : 'a -> 'a t
[lazy (v)].
@since 4.00.0 *)

val is_val : 'a t -> bool
(** [is_val x] returns [true] if [x] has already been forced and
did not raise an exception.
@since 4.00.0 *)

val lazy_from_fun : (unit -> 'a) -> 'a t
[@@ocaml.deprecated "Use Lazy.from_fun instead."]
(** @deprecated synonym for [from_fun]. *)
Expand Down
55 changes: 55 additions & 0 deletions testsuite/tests/lib-lazy/test.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
(* TEST
* expect
*)

(* expect-tests currently do not collect I/O,
so we emulate I/O by collecting output in a "log" *)
let logger () =
let log = ref [] in
let show_log v = List.rev !log, v in
let log v = log := v :: !log in
log, show_log

let _ =
let log, show_log = logger () in
let x = lazy (log "x"; 41) in
let y =
log "map";
Lazy.map (fun n -> log "y"; n+1) x in
show_log (Lazy.force y)
;;
[%%expect{|
val logger : unit -> ('a -> unit) * ('b -> 'a list * 'b) = <fun>
- : string list * int = (["map"; "x"; "y"], 42)
|}]

let _ =
let log, show_log = logger () in
let x = lazy (log "x"; 41) in
let () = log "iter"; Lazy.iter (Printf.ksprintf log "%d") x in
show_log ()
;;
[%%expect{|
- : string list * unit = (["iter"; "x"; "41"], ())
|}]

let _ =
let log, show_log = logger () in
let x = lazy (log "x"; 41) in
log "fold";
show_log (Lazy.fold (fun n v -> n + v) x 1)
;;
[%%expect{|
- : string list * int = (["fold"; "x"], 42)
|}]

let _ =
let log, show_log = logger () in
let x = lazy (log "x"; 41) in
let y = lazy (log "y"; 42) in
show_log (Lazy.equal Int.equal x y,
Lazy.equal (fun a b -> a+1=b) x y)
;;
[%%expect{|
- : string list * (bool * bool) = (["x"; "y"], (false, true))
|}]

0 comments on commit f51899f

Please sign in to comment.