Skip to content

Commit

Permalink
Merge pull request #31 from mbarbin/named-traits
Browse files Browse the repository at this point in the history
Name traits in preparation for refactor
  • Loading branch information
mbarbin authored Oct 31, 2024
2 parents 2f33644 + 5b72994 commit 04b3415
Show file tree
Hide file tree
Showing 19 changed files with 274 additions and 142 deletions.
18 changes: 12 additions & 6 deletions doc/docs/reference/hello_world.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,31 @@ end
type show = [ `Show ]
type (_, _, _) Provider.Trait.t +=
Show : ('t, (module S with type t = 't), [> show ]) Provider.Trait.t
module Show : sig
val t : ('t, (module S with type t = 't), [> show ]) Provider.Trait.t
end = struct
type (_, _, _) Provider.Trait.t +=
| Show : ('t, (module S with type t = 't), [> show ]) Provider.Trait.t
let t = Show
end
let print (Provider.T { t; handler }) =
let module M = (val Provider.Handler.lookup handler ~trait:Show) in
let module M = (val Provider.Handler.lookup handler ~trait:Show.t) in
print_endline (M.show t)
let string_provider t =
let handler =
Provider.Handler.make
[ Provider.Trait.implement Show
~impl:(module struct type t = string let show = Fun.id end)
[ Provider.Trait.implement Show.t
~impl:(module struct type t = string let show = String.uppercase_ascii end)
]
in
Provider.T { t; handler }
```

```ocaml
# print (string_provider "Hello World")
Hello World
HELLO WORLD
- : unit = ()
```
22 changes: 14 additions & 8 deletions doc/docs/tutorials/getting-started/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,14 @@ To use Provider, first we have to create a new tag and a new type constructor th
```ocaml
type reader = [ `Reader ]
type (_, _, _) Provider.Trait.t +=
Reader : ('t, (module READER with type t = 't), [> reader ]) Provider.Trait.t
module Reader : sig
val t : ('t, (module READER with type t = 't), [> reader ]) Provider.Trait.t
end = struct
type (_, _, _) Provider.Trait.t +=
Reader : ('t, (module READER with type t = 't), [> reader ]) Provider.Trait.t
let t = Reader
end
```

### Parametrized Library
Expand All @@ -142,11 +148,11 @@ module Show_files2 : sig
end = struct
let print_files_with_ext (Provider.T { t = reader; handler }) ~path ~ext =
let module Reader = (val Provider.Handler.lookup handler ~trait:Reader) in
let entries = Reader.readdir reader ~path |> List.sort String.compare in
let module R = (val Provider.Handler.lookup handler ~trait:Reader.t) in
let entries = R.readdir reader ~path |> List.sort String.compare in
let files = List.filter (String.ends_with ~suffix:ext) entries in
files |> List.iter (fun file ->
let contents = Reader.load_file reader ~path:(Filename.concat path file) in
let contents = R.load_file reader ~path:(Filename.concat path file) in
let line_count =
List.length (String.split_on_char '\n' contents)
- (if String.ends_with ~suffix:"\n" contents then 1 else 0)
Expand All @@ -168,8 +174,8 @@ module Show_files3 : sig
end = struct
let print_files_with_ext (Provider.T { t = reader; handler }) ~path ~ext =
let module Reader = (val Provider.Handler.lookup handler ~trait:Reader) in
let module M = Show_files (Reader) in
let module R = (val Provider.Handler.lookup handler ~trait:Reader.t) in
let module M = Show_files (R) in
M.print_files_with_ext reader ~path ~ext
end
Expand All @@ -187,7 +193,7 @@ let sys_reader () : [ `Reader ] Provider.t =
{ t = ()
; handler =
Provider.Handler.make
[ Provider.Trait.implement Reader ~impl:(module Sys_reader) ]
[ Provider.Trait.implement Reader.t ~impl:(module Sys_reader) ]
}
```

Expand Down
89 changes: 62 additions & 27 deletions doc/docs/tutorials/handler-explicit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ module type Id = sig type t val id : t -> t end
type id = [ `Id ]
type (_, _, _) Provider.Trait.t +=
| Id : ('a, (module Id with type t = 'a), [> id]) Provider.Trait.t
module Id : sig
val t : ('a, (module Id with type t = 'a), [> id]) Provider.Trait.t
end = struct
type (_, _, _) Provider.Trait.t +=
| Id : ('a, (module Id with type t = 'a), [> id]) Provider.Trait.t
let t = Id
end
let id : type a. (a, [> id]) Provider.Handler.t -> a -> a =
fun handler x ->
let module M = (val Provider.Handler.lookup handler ~trait:Id) in
let module M = (val Provider.Handler.lookup handler ~trait:Id.t) in
M.id x
;;
```
Expand Down Expand Up @@ -59,8 +65,15 @@ We define the expected *Provider* machinery, including a `Provider.Trait` for it
```ocaml
type doublable = [ `Doublable ]
type (_, _, _) Provider.Trait.t +=
| Doublable : ('a, (module Doublable with type t = 'a), [> doublable ]) Provider.Trait.t
module Doublable : sig
val t : ('a, (module Doublable with type t = 'a), [> doublable ]) Provider.Trait.t
end = struct
type (_, _, _) Provider.Trait.t +=
| Doublable : ('a, (module Doublable with type t = 'a), [> doublable ]) Provider.Trait.t
let t = Doublable
end
```

### Writing Parametrized Code
Expand All @@ -70,7 +83,7 @@ With no dependencies on actual providers, we can define functionality depending
```ocaml
# let quadruple : type a. (a, [> doublable ]) Provider.Handler.t -> a -> a =
fun handler t ->
let module M = (val Provider.Handler.lookup handler ~trait:Doublable) in
let module M = (val Provider.Handler.lookup handler ~trait:Doublable.t) in
M.double (M.double t)
val quadruple : ('a, [> doublable ]) Provider.Handler.t -> 'a -> 'a = <fun>
```
Expand Down Expand Up @@ -98,12 +111,12 @@ We build *handlers* values for these modules:
```ocaml
# let doublable_int () : (int, [> doublable ]) Provider.Handler.t =
Provider.Handler.make
[ Provider.Trait.implement Doublable ~impl:(module Doublable_int) ]
[ Provider.Trait.implement Doublable.t ~impl:(module Doublable_int) ]
val doublable_int : unit -> (int, [> doublable ]) Provider.Handler.t = <fun>
# let doublable_float () : (float, [> doublable ]) Provider.Handler.t =
Provider.Handler.make
[ Provider.Trait.implement Doublable ~impl:(module Doublable_float) ]
[ Provider.Trait.implement Doublable.t ~impl:(module Doublable_float) ]
val doublable_float : unit -> (float, [> doublable ]) Provider.Handler.t =
<fun>
```
Expand Down Expand Up @@ -137,8 +150,14 @@ end
```ocaml
type repeatable = [ `Repeatable ]
type (_, _, _) Provider.Trait.t +=
| Repeatable : ('a, (module Repeatable with type t = 'a), [> repeatable ]) Provider.Trait.t
module Repeatable : sig
val t : ('a, (module Repeatable with type t = 'a), [> repeatable ]) Provider.Trait.t
end = struct
type (_, _, _) Provider.Trait.t +=
| Repeatable : ('a, (module Repeatable with type t = 'a), [> repeatable ]) Provider.Trait.t
let t = Repeatable
end
```

### Writing Parametrized Code
Expand All @@ -148,9 +167,9 @@ The function below requires both `repeatable` and `doublable` Traits:
```ocaml
# let double_then_repeat : type a. (a, [> doublable | repeatable ]) Provider.Handler.t -> a -> a =
fun handler t ->
let module D = (val Provider.Handler.lookup handler ~trait:Doublable) in
let module R = (val Provider.Handler.lookup handler ~trait:Repeatable) in
R.repeat (D.double t)
let module D = (val Provider.Handler.lookup handler ~trait:Doublable.t) in
let module R = (val Provider.Handler.lookup handler ~trait:Repeatable.t) in
t |> D.double |> R.repeat
val double_then_repeat :
('a, [> `Doublable | `Repeatable ]) Provider.Handler.t -> 'a -> 'a = <fun>
```
Expand All @@ -174,8 +193,8 @@ We can now build a *handler* for it:
```ocaml
# let versatile_int () : (int, [> doublable | repeatable ]) Provider.Handler.t =
Provider.Handler.make
[ Provider.Trait.implement Doublable ~impl:(module Versatile_int)
; Provider.Trait.implement Repeatable ~impl:(module Versatile_int)
[ Provider.Trait.implement Doublable.t ~impl:(module Versatile_int)
; Provider.Trait.implement Repeatable.t ~impl:(module Versatile_int)
]
val versatile_int :
unit -> (int, [> `Doublable | `Repeatable ]) Provider.Handler.t = <fun>
Expand Down Expand Up @@ -247,23 +266,39 @@ type mappable = [ `Mappable ]
Note, you cannot write this (the `'a 't` syntax doesn't mean anything):

```ocaml
type (_, _, _) Provider.Trait.t +=
| Mappable : ('a 't, (module Mappable with type 'a t = 'a 't), [> mappable ]) Provider.Trait.t
module Mappable : sig
val t : ('a 't, (module Mappable with type 'a t = 'a 't), [> mappable ]) Provider.Trait.t
end = struct
type (_, _, _) Provider.Trait.t +=
| Mappable : ('a 't, (module Mappable with type 'a t = 'a 't), [> mappable ]) Provider.Trait.t
let t = Mappable
end
```
```mdx-error
Line 2, characters 22-23:
Line 2, characters 17-18:
Error: Syntax error
```

This is where `Higher_kinded` comes to the rescue:

```ocaml
type (_, _, _) Provider.Trait.t +=
| Mappable :
( ('a -> 'higher_kinded) Higher_kinded.t
, (module Mappable with type higher_kinded = 'higher_kinded)
, [> mappable ] )
Provider.Trait.t
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
```

### Writing Parametrized Code
Expand All @@ -280,7 +315,7 @@ let map_n_times
-> (a -> t) Higher_kinded.t
=
fun handler t n ~f ->
let module M = (val Provider.Handler.lookup handler ~trait:Mappable) in
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 f at) in
M.inject (loop n at)
Expand Down Expand Up @@ -321,7 +356,7 @@ We build *handlers* values for these modules:
Provider.Handler.t
=
Provider.Handler.make
[ Provider.Trait.implement Mappable ~impl:(module Higher_kinded_list) ]
[ Provider.Trait.implement Mappable.t ~impl:(module Higher_kinded_list) ]
val mappable_list :
unit ->
(('a -> Higher_kinded_list.higher_kinded) Higher_kinded.t, [> mappable ])
Expand All @@ -333,7 +368,7 @@ val mappable_list :
Provider.Handler.t
=
Provider.Handler.make
[ Provider.Trait.implement Mappable ~impl:(module Higher_kinded_array) ]
[ Provider.Trait.implement Mappable.t ~impl:(module Higher_kinded_array) ]
val mappable_array :
unit ->
(('a -> Higher_kinded_array.higher_kinded) Higher_kinded.t, [> mappable ])
Expand Down
2 changes: 1 addition & 1 deletion test/eio/test__reader.ml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ let print_all_text_files_with_lines_if_available t ~path =
match
Provider.Handler.lookup_opt
handler
~trait:Test_interfaces.File_reader.Provider_interface.File_reader
~trait:Test_interfaces.File_reader.Provider_interface.file_reader
with
| None -> "not-available"
| Some (module File_reader) ->
Expand Down
4 changes: 2 additions & 2 deletions test/eio/test_providers/eio_reader.ml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ let make ~env : [ `Directory_reader | `File_reader ] Provider.t =
; handler =
Provider.Handler.make
[ Provider.Trait.implement
Test_interfaces.Directory_reader.Provider_interface.Directory_reader
Test_interfaces.Directory_reader.Provider_interface.directory_reader
~impl:(module Impl)
; Provider.Trait.implement
Test_interfaces.File_reader.Provider_interface.File_reader
Test_interfaces.File_reader.Provider_interface.file_reader
~impl:(module Impl)
]
}
Expand Down
16 changes: 8 additions & 8 deletions test/test__cache.ml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ let%expect_test "override" =
let cache_state_of_uid uid =
if Provider.Trait.Uid.equal
uid
(Test_interfaces.Int_printer.Provider_interface.Int_printer |> Provider.Trait.uid)
(Test_interfaces.Int_printer.Provider_interface.int_printer |> Provider.Trait.uid)
then Cache_state.Int_printer
else if Provider.Trait.Uid.equal
uid
(Test_interfaces.Float_printer.Provider_interface.Float_printer
(Test_interfaces.Float_printer.Provider_interface.float_printer
|> Provider.Trait.uid)
then Cache_state.Float_printer
else assert false [@coverage off]
Expand All @@ -45,7 +45,7 @@ let%expect_test "override" =
ignore
(Provider.Handler.lookup
handler
~trait:Test_interfaces.Int_printer.Provider_interface.Int_printer
~trait:Test_interfaces.Int_printer.Provider_interface.int_printer
: (module Test_interfaces.Int_printer.Provider_interface.S with type t = a)))
handler;
require_equal
Expand All @@ -59,7 +59,7 @@ let%expect_test "override" =
ignore
(Provider.Handler.lookup
handler
~trait:Test_interfaces.Float_printer.Provider_interface.Float_printer
~trait:Test_interfaces.Float_printer.Provider_interface.float_printer
: (module Test_interfaces.Float_printer.Provider_interface.S with type t = a)))
handler;
require_equal
Expand All @@ -74,7 +74,7 @@ let%expect_test "override" =
(Option.is_some
(Provider.Handler.lookup_opt
handler
~trait:Test_interfaces.Int_printer.Provider_interface.Int_printer));
~trait:Test_interfaces.Int_printer.Provider_interface.int_printer));
require_equal
[%here]
(module Cache_state)
Expand All @@ -87,7 +87,7 @@ let%expect_test "override" =
(Option.is_some
(Provider.Handler.lookup_opt
handler
~trait:Test_interfaces.Float_printer.Provider_interface.Float_printer));
~trait:Test_interfaces.Float_printer.Provider_interface.float_printer));
require_equal
[%here]
(module Cache_state)
Expand All @@ -100,7 +100,7 @@ let%expect_test "override" =
[%here]
(Provider.Handler.implements
handler
~trait:Test_interfaces.Int_printer.Provider_interface.Int_printer);
~trait:Test_interfaces.Int_printer.Provider_interface.int_printer);
let post_cache_state = cache_state handler in
require_equal [%here] (module Cache_state) pre_cache_state post_cache_state
in
Expand All @@ -110,7 +110,7 @@ let%expect_test "override" =
[%here]
(Provider.Handler.implements
handler
~trait:Test_interfaces.Float_printer.Provider_interface.Float_printer);
~trait:Test_interfaces.Float_printer.Provider_interface.float_printer);
let post_cache_state = cache_state handler in
require_equal [%here] (module Cache_state) pre_cache_state post_cache_state
in
Expand Down
Loading

0 comments on commit 04b3415

Please # to comment.