open! Import module Test_applicative_s (A : Applicative.S with type 'a t := 'a Or_error.t) : Applicative.S with type 'a t := 'a Or_error.t = struct let error = Or_error.error_string let return = A.return let%expect_test _ = print_s [%sexp (return "okay" : string Or_error.t)]; [%expect {| (Ok okay) |}] ;; let apply = A.apply let%expect_test _ = let test x y = print_s [%sexp (apply x y : string Or_error.t)] in test (Ok String.capitalize) (Ok "okay"); [%expect {| (Ok Okay) |}]; test (error "not okay") (Ok "okay"); [%expect {| (Error "not okay") |}]; test (Ok String.capitalize) (error "not okay"); [%expect {| (Error "not okay") |}]; test (error "no fun") (error "no arg"); [%expect {| (Error ("no fun" "no arg")) |}] ;; let ( <*> ) = A.( <*> ) let%expect_test _ = let test x y = print_s [%sexp (x <*> y : string Or_error.t)] in test (Ok String.capitalize) (Ok "okay"); [%expect {| (Ok Okay) |}]; test (error "not okay") (Ok "okay"); [%expect {| (Error "not okay") |}]; test (Ok String.capitalize) (error "not okay"); [%expect {| (Error "not okay") |}]; test (error "no fun") (error "no arg"); [%expect {| (Error ("no fun" "no arg")) |}] ;; let ( *> ) = A.( *> ) let%expect_test _ = let test x y = print_s [%sexp (x *> y : string Or_error.t)] in test (Ok ()) (Ok "kay"); [%expect {| (Ok kay) |}]; test (error "not okay") (Ok "kay"); [%expect {| (Error "not okay") |}]; test (Ok ()) (error "not okay"); [%expect {| (Error "not okay") |}]; test (error "no fst") (error "no snd"); [%expect {| (Error ("no fst" "no snd")) |}] ;; let ( <* ) = A.( <* ) let%expect_test _ = let test x y = print_s [%sexp (x <* y : string Or_error.t)] in test (Ok "okay") (Ok ()); [%expect {| (Ok okay) |}]; test (error "not okay") (Ok ()); [%expect {| (Error "not okay") |}]; test (Ok "okay") (error "not okay"); [%expect {| (Error "not okay") |}]; test (error "no fst") (error "no snd"); [%expect {| (Error ("no fst" "no snd")) |}] ;; let both = A.both let%expect_test _ = let test x y = print_s [%sexp (both x y : (string * string) Or_error.t)] in test (Ok "o") (Ok "kay"); [%expect {| (Ok (o kay)) |}]; test (error "not okay") (Ok "kay"); [%expect {| (Error "not okay") |}]; test (Ok "o") (error "not okay"); [%expect {| (Error "not okay") |}]; test (error "no fst") (error "no snd"); [%expect {| (Error ("no fst" "no snd")) |}] ;; let map = A.map let%expect_test _ = let test x = print_s [%sexp (map x ~f:String.capitalize : string Or_error.t)] in test (Ok "okay"); [%expect {| (Ok Okay) |}]; test (error "not okay"); [%expect {| (Error "not okay") |}] ;; let ( >>| ) = A.( >>| ) let%expect_test _ = let test x = print_s [%sexp (x >>| String.capitalize : string Or_error.t)] in test (Ok "okay"); [%expect {| (Ok Okay) |}]; test (error "not okay"); [%expect {| (Error "not okay") |}] ;; let map2 = A.map2 let%expect_test _ = let test x y = print_s [%sexp (map2 x y ~f:( ^ ) : string Or_error.t)] in test (Ok "o") (Ok "kay"); [%expect {| (Ok okay) |}]; test (error "not okay") (Ok "kay"); [%expect {| (Error "not okay") |}]; test (Ok "o") (error "not okay"); [%expect {| (Error "not okay") |}]; test (error "no fst") (error "no snd"); [%expect {| (Error ("no fst" "no snd")) |}] ;; let map3 = A.map3 let%expect_test _ = let test x y z = print_s [%sexp (map3 x y z ~f:(fun a b c -> a ^ b ^ c) : string Or_error.t)] in test (Ok "o") (Ok "k") (Ok "ay"); [%expect {| (Ok okay) |}]; test (error "not okay") (Ok "k") (Ok "ay"); [%expect {| (Error "not okay") |}]; test (Ok "o") (error "not okay") (Ok "ay"); [%expect {| (Error "not okay") |}]; test (Ok "o") (Ok "k") (error "not okay"); [%expect {| (Error "not okay") |}]; test (error "no 1st") (error "no 2nd") (error "no 3rd"); [%expect {| (Error ("no 1st" "no 2nd" "no 3rd")) |}] ;; let all = A.all let%expect_test _ = let test list = print_s [%sexp (all list : string list Or_error.t)] in test []; [%expect {| (Ok ()) |}]; test [ Ok "okay" ]; [%expect {| (Ok (okay)) |}]; test [ Ok "o"; Ok "kay" ]; [%expect {| (Ok (o kay)) |}]; test [ Ok "o"; Ok "k"; Ok "ay" ]; [%expect {| (Ok (o k ay)) |}]; test [ error "oh no!" ]; [%expect {| (Error "oh no!") |}]; test [ error "oh no!"; Ok "okay" ]; [%expect {| (Error "oh no!") |}]; test [ Ok "okay"; error "oh no!" ]; [%expect {| (Error "oh no!") |}]; test [ error "oh no!"; Ok "o"; Ok "kay" ]; [%expect {| (Error "oh no!") |}]; test [ Ok "o"; error "oh no!"; Ok "aay" ]; [%expect {| (Error "oh no!") |}]; test [ Ok "o"; Ok "kay"; error "oh no!" ]; [%expect {| (Error "oh no!") |}]; test [ error "oh"; error "no"; error "!" ]; [%expect {| (Error (oh no !)) |}] ;; let all_unit = A.all_unit let%expect_test _ = let test list = print_s [%sexp (all_unit list : unit Or_error.t)] in test []; [%expect {| (Ok ()) |}]; test [ Ok () ]; [%expect {| (Ok ()) |}]; test [ Ok (); Ok () ]; [%expect {| (Ok ()) |}]; test [ Ok (); Ok (); Ok () ]; [%expect {| (Ok ()) |}]; test [ error "oh no!" ]; [%expect {| (Error "oh no!") |}]; test [ error "oh no!"; Ok () ]; [%expect {| (Error "oh no!") |}]; test [ Ok (); error "oh no!" ]; [%expect {| (Error "oh no!") |}]; test [ error "oh no!"; Ok (); Ok () ]; [%expect {| (Error "oh no!") |}]; test [ Ok (); error "oh no!"; Ok () ]; [%expect {| (Error "oh no!") |}]; test [ Ok (); Ok (); error "oh no!" ]; [%expect {| (Error "oh no!") |}]; test [ error "oh"; error "no"; error "!" ]; [%expect {| (Error (oh no !)) |}] ;; module Applicative_infix = A.Applicative_infix end let%test_module "Make" = (module Test_applicative_s (Applicative.Make (struct type 'a t = 'a Or_error.t let return = Or_error.return let apply = Or_error.apply let map = `Define_using_apply end))) ;; let%test_module "Make" = (module Test_applicative_s (Applicative.Make_using_map2 (struct type 'a t = 'a Or_error.t let return = Or_error.return let map2 = Or_error.map2 let map = `Define_using_map2 end))) ;; let%test_module "Make" = (module Test_applicative_s (Applicative.Make_using_map2_local (struct type 'a t = 'a Or_error.t let return x = Ok x let map2 = Or_error.map2 let map = `Define_using_map2 end))) ;; (* While law-abiding applicatives shouldn't be relying functions being called the minimal number of times, it is good for performance that things be this way. For many applicatives this will not matter very much, but for others, like Bonsai, it is a little more significant, since extra calls construct more Incremental nodes, yielding more strain on the Incremental stabilizer. The point is that we should not assume that the input applicative instance can be frivolous in creating nodes in the applicative call-tree. *) let%expect_test _ = let module A = struct type 'a t = | Other of string | Return : 'a -> 'a t | Map : ('a -> 'b) * 'a t -> 'b t | Map2 : ('a -> 'b -> 'c) * 'a t * 'b t -> 'c t include Applicative.Make_using_map2 (struct type nonrec 'a t = 'a t let return x = Return x let map2 a b ~f = Map2 (f, a, b) let map = `Custom (fun a ~f -> Map (f, a)) end) let rec sexp_of_t : type a. a t -> Sexp.t = function | Other x -> Atom x | Return _ -> Atom "Return" | Map (_, a) -> List [ Atom "Map"; sexp_of_t a ] | Map2 (_, a, b) -> List [ Atom "Map2"; sexp_of_t a; sexp_of_t b ] ;; end in let open A in let test x = print_s [%sexp (x : A.t)] in let a, b, c, d = Other "A", Other "B", Other "C", Other "D" in test (map2 a b ~f:(fun a b -> a, b)); [%expect {| (Map2 A B) |}]; test (both a b); [%expect {| (Map2 A B) |}]; test (all_unit [ a; b; c; d ]); [%expect {| (Map2 (Map2 (Map2 (Map2 Return A) B) C) D) |}]; test (a *> b); [%expect {| (Map2 A B) |}] ;; (* These functors serve only to check that the signatures for various Foo and Foo2 module types don't drift apart over time. *) module _ = struct open Applicative (* Applicative_infix to Applicative_infix2 *) module _ (X : Applicative_infix) : Applicative_infix2 with type ('a, 'e) t = 'a X.t = struct include X type ('a, 'e) t = 'a X.t end (* Applicative_infix2 to Applicative_infix *) module _ (X : Applicative_infix2) : Applicative_infix with type 'a t = ('a, unit) X.t = struct include X type 'a t = ('a, unit) X.t end (* Applicative_infix2 to Applicative_infix3 *) module _ (X : Applicative_infix2) : Applicative_infix3 with type ('a, 'd, 'e) t = ('a, 'd) X.t = struct include X type ('a, 'd, 'e) t = ('a, 'd) X.t end (* Applicative_infix3 to Applicative_infix2 *) module _ (X : Applicative_infix3) : Applicative_infix2 with type ('a, 'd) t = ('a, 'd, unit) X.t = struct include X type ('a, 'd) t = ('a, 'd, unit) X.t end (* Let_syntax to Let_syntax2 *) module _ (X : Let_syntax) : Let_syntax2 with type ('a, 'e) t = 'a X.t = struct include X type ('a, 'e) t = 'a X.t end (* Let_syntax2 to Let_syntax *) module _ (X : Let_syntax2) : Let_syntax with type 'a t = ('a, unit) X.t = struct include X type 'a t = ('a, unit) X.t end (* Let_syntax2 to Let_syntax3 *) module _ (X : Let_syntax2) : Let_syntax3 with type ('a, 'd, 'e) t = ('a, 'd) X.t = struct include X type ('a, 'd, 'e) t = ('a, 'd) X.t end (* Let_syntax3 to Let_syntax2 *) module _ (X : Let_syntax3) : Let_syntax2 with type ('a, 'd) t = ('a, 'd, unit) X.t = struct include X type ('a, 'd) t = ('a, 'd, unit) X.t end end