Skip to content

Commit

Permalink
Check higher_kinded during tests as well
Browse files Browse the repository at this point in the history
  • Loading branch information
mbarbin committed Oct 31, 2024
1 parent a1fdab2 commit 194cc52
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 0 deletions.
1 change: 1 addition & 0 deletions test/dune
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
base
expect_test_helpers_core.expect_test_helpers_base
provider
provider-tests.higher_kinded
test_interfaces
test_providers
unix)
Expand Down
110 changes: 110 additions & 0 deletions test/test__higher_kinded.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
(* In this test we check that the trait system allows to be used with module
interfaces that are parametrized.
There is also a tutorial for this, but we like to have both. Motivations are:
- here we get better error messages and development experience when working
on this (the tutorial is an mdx file, which has a slightly less advanced
editor integration).
- this test is checked by [more-ci] whereas the tutorial is not. *)

module type Mappable = sig
type 'a t

val map : 'a t -> f:('a -> 'b) -> 'b t

type higher_kinded

val inject : 'a t -> ('a -> higher_kinded) Higher_kinded.t
val project : ('a -> higher_kinded) Higher_kinded.t -> 'a t
end

type mappable = [ `Mappable ]

module Mappable : sig
val t
: ( ('a -> 'higher_kinded) Higher_kinded.t
, (module Mappable with type higher_kinded = 'higher_kinded)
, [> mappable ] )
Provider.Trait.t
end = struct
type (_, _, _) Provider.Trait.t +=
| Mappable :
( ('a -> 'higher_kinded) Higher_kinded.t
, (module Mappable with type higher_kinded = 'higher_kinded)
, [> mappable ] )
Provider.Trait.t

let t = Mappable
end

let map_n_times
: type a t.
((a -> t) Higher_kinded.t, [> mappable ]) Provider.Handler.t
-> (a -> t) Higher_kinded.t
-> int
-> f:(a -> a)
-> (a -> t) Higher_kinded.t
=
fun handler t n ~f ->
let module M = (val Provider.Handler.lookup handler ~trait:Mappable.t) in
let at = M.project t in
let rec loop n at = if n = 0 then at else loop (n - 1) (M.map at ~f) in
M.inject (loop n at)
;;

module Higher_kinded_list = struct
include List
include Higher_kinded.Make (List)
end

module Higher_kinded_array = struct
include Array
include Higher_kinded.Make (Array)
end

module _ : Mappable with type 'a t = 'a list = Higher_kinded_list
module _ : Mappable with type 'a t = 'a array = Higher_kinded_array

let mappable_list ()
: ( ('a -> Higher_kinded_list.higher_kinded) Higher_kinded.t
, [> mappable ] )
Provider.Handler.t
=
Provider.Handler.make
[ Provider.Trait.implement Mappable.t ~impl:(module Higher_kinded_list) ]
;;

let mappable_array ()
: ( ('a -> Higher_kinded_array.higher_kinded) Higher_kinded.t
, [> mappable ] )
Provider.Handler.t
=
Provider.Handler.make
[ Provider.Trait.implement Mappable.t ~impl:(module Higher_kinded_array) ]
;;

let%expect_test "map_n_times" =
let r =
map_n_times
(mappable_list ())
(List.init 10 ~f:Fn.id |> Higher_kinded_list.inject)
3
~f:(fun x -> x + 1)
|> Higher_kinded_list.project
in
print_s [%sexp (r : int list)];
[%expect {| (3 4 5 6 7 8 9 10 11 12) |}];
let r =
map_n_times
(mappable_array ())
([| "a"; "b" |] |> Higher_kinded_array.inject)
4
~f:(fun x -> x ^ x)
|> Higher_kinded_array.project
in
print_s [%sexp (r : string array)];
[%expect {| (aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbb) |}];
()
;;
Empty file added test/test__higher_kinded.mli
Empty file.

0 comments on commit 194cc52

Please sign in to comment.