Skip to content

Commit

Permalink
adds binding operators to the monads library (#1234)
Browse files Browse the repository at this point in the history
Instead of extending the `Syntax` module of the `Monad.S` and
`Monad.S2` interface, which will break the interfaces, we add a new
module `Let` which includes binding operators for Monadic and
applicative interfaces (`let*`/`and*` and `let+`/`and+`
correspondingly).

That means that in order to be able to use the monadic operators for
the monad `Example` we need to open either `Example` or `Example.Let`
first, so we can write

```
open Example.Let

let example x y =
  let* r = compute x in
  let+ s = compute y in
  r + s
```

instead of the old style with `fun`,

```
open Example.Syntax

let example x y =
  compute x >>= fun r ->
  compute y >>| fun s ->
  r + s
```

Parallel binding is provided via the `(and*)` and `(and+)` operators,
so it is possible to write

```
open Example.Let

let example x y =
  let* r = compute x in
  and* s = compute y in
  Example.return (r + s)
```
  • Loading branch information
ivg authored Nov 10, 2020
1 parent 36285d6 commit 874454e
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 3 deletions.
69 changes: 66 additions & 3 deletions lib/monads/monads.mli
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ open Core_kernel
To use the library add [open Monads.Std] to your program. It will
bring [Monoid] and [Monad] modules to your scope. A conventional
way of writing a computation in a monad [M], is to open its syntax
with [open M.Syntax].
with [open M.Syntax] and/or [open M.Let] (for the monadic binding
operators).
Given that monad is a concept that goes beyond OCaml language,
i.e., it is more a design pattern rather than just a module type
Expand Down Expand Up @@ -982,6 +983,8 @@ module Std : sig
val (!$$$$$) : ('a -> 'b -> 'c -> 'd -> 'e -> 'f) -> ('a t -> 'b t -> 'c t -> 'd t -> 'e t -> 'f t)
end


(** Operators for binary monad. *)
module type S2 = sig
type ('a,'e) t

Expand Down Expand Up @@ -1013,9 +1016,61 @@ module Std : sig
val (!$$$$$) : ('a -> 'b -> 'c -> 'd -> 'e -> 'f) ->
(('a,'s) t -> ('b,'s) t -> ('c,'s) t -> ('d,'s) t -> ('e,'s) t -> ('f,'s) t)
end


(** Monadic bindings operators.
This operators allows to write
{[let* r = computation x in body]}
instead of the old infix style
{[computation x >>= fun r -> body]}
The [let*] and [and*] operators stand for the monad
part of the binding operators interface and [let+] with [and+]
stand for the applicative part of the binding operators
interface.
@since 2.2.0 and OCaml 4.08.0
*)
module Let : sig
module type S = sig
type 'a t

(** [let* r = f x in b] is [f x >>= fun r -> b] *)
val (let*) : 'a t -> ('a -> 'b t) -> 'b t

(** monoidal product *)
val (and*) : 'a t -> 'b t -> ('a * 'b) t

(** [let+ r = f x in b] is [f x >>| fun r -> b] *)
val (let+) : 'a t -> ('a -> 'b) -> 'b t

(** monoidal product *)
val (and+) : 'a t -> 'b t -> ('a * 'b) t
end

module type S2 = sig
type ('a,'e) t

(** [let* r = f x in b] is [f x >>= fun r -> b] *)
val (let*) : ('a,'e) t -> ('a -> ('b,'e) t) -> ('b,'e) t

(** monoidal product *)
val (and*) : ('a,'e) t -> ('b,'e) t -> ('a * 'b, 'e) t

(** [let+ r = f x in b] is [f x >>| fun r -> b] *)
val (let+) : ('a,'e) t -> ('a -> 'b) -> ('b,'e) t

(** monoidal product *)
val (and+) : ('a,'e) t -> ('b,'e) t -> ('a * 'b, 'e) t
end
end
end

(** An unary monad interface. *)
(** A unary monad interface. *)
module type S = sig
type 'a t

Expand Down Expand Up @@ -1146,8 +1201,9 @@ module Std : sig
module Seq : Collection.S with type 'a t := 'a Sequence.t

include Syntax.S with type 'a t := 'a t
include Syntax.Let.S with type 'a t := 'a t
include Monad.S with type 'a t := 'a t

module Let : Syntax.Let.S with type 'a t := 'a t
(** Monadic operators, see
{{!Std.Monad.Syntax.S}Monad.Syntax.S} for more. *)
module Syntax : Syntax.S with type 'a t := 'a t
Expand Down Expand Up @@ -1287,8 +1343,15 @@ module Std : sig
module Seq : Collection.S with type 'a t := 'a Sequence.t

include Syntax.S2 with type ('a,'e) t := ('a,'e) t
include Syntax.Let.S2 with type ('a,'e) t := ('a,'e) t
include Monad.S2 with type ('a,'e) t := ('a,'e) t


(** Monadic Binding Operators.
@since 2.2.0
*)
module Let : Syntax.Let.S2 with type ('a,'e) t := ('a,'e) t

(** Monadic operators, see
{{!Std.Monad.Syntax.S2}Monad.Syntax.S2} for more. *)
module Syntax : Syntax.S2 with type ('a,'e) t := ('a,'e) t
Expand Down
24 changes: 24 additions & 0 deletions lib/monads/monads_monad.ml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ module Monad = struct
include Lift.Syntax
let (>=>) g f = Fn.compose f g [@@inline]
end

module Let = struct
let (let*) = (>>=)
let (let+) = (>>|)
let (and+) x y =
x >>= fun x ->
y >>| fun y ->
(x,y)
let (and*) = (and+)
end

open Syntax

module Pair = struct
Expand Down Expand Up @@ -252,6 +263,7 @@ module Monad = struct
let sequence = List.sequence
let rec forever t = bind t (fun _ -> forever t)
include Syntax
include Let
end

module Make(M : B) : S with type 'a t := 'a M.t =
Expand Down Expand Up @@ -433,6 +445,17 @@ module Ident
let (!$$$$$) = ident
end

module Let = struct
open Syntax
let (let*) = (>>=)
let (let+) = (>>|)
let (and+) x y =
x >>= fun x ->
y >>| fun y ->
(x,y)
let (and*) = (and+)
end

module Let_syntax = struct
include Syntax
let return = ident
Expand All @@ -457,6 +480,7 @@ module Ident
module Monad_infix = Syntax
include Let_syntax.Let_syntax
include Syntax
include Let
end

module OptionT = struct
Expand Down
22 changes: 22 additions & 0 deletions lib/monads/monads_types.ml
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,24 @@ module Monad = struct
val (!$$$$$) : ('a -> 'b -> 'c -> 'd -> 'e -> 'f) ->
(('a,'s) t -> ('b,'s) t -> ('c,'s) t -> ('d,'s) t -> ('e,'s) t -> ('f,'s) t)
end

module Let = struct
module type S = sig
type 'a t
val (let*) : 'a t -> ('a -> 'b t) -> 'b t
val (and*) : 'a t -> 'b t -> ('a * 'b) t
val (let+) : 'a t -> ('a -> 'b) -> 'b t
val (and+) : 'a t -> 'b t -> ('a * 'b) t
end

module type S2 = sig
type ('a,'e) t
val (let*) : ('a,'e) t -> ('a -> ('b,'e) t) -> ('b,'e) t
val (and*) : ('a,'e) t -> ('b,'e) t -> ('a * 'b, 'e) t
val (let+) : ('a,'e) t -> ('a -> 'b) -> ('b,'e) t
val (and+) : ('a,'e) t -> ('b,'e) t -> ('a * 'b, 'e) t
end
end
end

module type S = sig
Expand Down Expand Up @@ -271,7 +289,9 @@ module Monad = struct


include Syntax.S with type 'a t := 'a t
include Syntax.Let.S with type 'a t := 'a t
include Monad.S with type 'a t := 'a t
module Let : Syntax.Let.S with type 'a t := 'a t
module Syntax : Syntax.S with type 'a t := 'a t
end

Expand Down Expand Up @@ -330,7 +350,9 @@ module Monad = struct


include Syntax.S2 with type ('a,'e) t := ('a,'e) t
include Syntax.Let.S2 with type ('a,'e) t := ('a,'e) t
include Monad.S2 with type ('a,'e) t := ('a,'e) t
module Let : Syntax.Let.S2 with type ('a,'e) t := ('a,'e) t
module Syntax : Syntax.S2 with type ('a,'e) t := ('a,'e) t
end
end
Expand Down

0 comments on commit 874454e

Please sign in to comment.