在 OCaml 中做符号
Do Notation in OCaml
OCaml 有等同于 Haskell 的 Do Notation 吗?
另一种说法 - 有没有一种简单的方法可以更轻松地处理嵌套单子操作...因为这很烦人:
open Batteries
open BatResult.Infix
let () =
let out =
(Ok("one")) >>=
(fun a ->
let b = Ok("two") in
b >>= (fun c ->
print_endline(a);
print_endline(c);
Ok(c)
)) in
ignore(out)
是的,从 OCaml 4.08 开始,可以描述 let
个运算符。例如:
let (let*) x f = BatResult.bind x f
let (let+) x f = BatResult.map f x
这使得以接近于直接风格的风格编写程序成为可能:
let out =
let* a = Ok "one" in
let* b = Ok "two" in
let () = print_endline a in
let () = print_endline b in
Ok b
您可以描述大量运算符,对于单子(例如 let*
代表 bind
和 let+
代表 map
),对于应用(例如 let+
用于 map
和 and+
用于 product
(或 zip
))等等
否则可以使用语法扩展,例如https://github.com/janestreet/ppx_let which, for the moment, offers even more possibilities than the let operators. If you ever want examples of let operators, in Preface(不要脸的插件),我们定义了很多!
edit:如@ivg 所说,您可以使用任何 $ ∣ & ∣ * ∣ + ∣ - ∣ / ∣ = ∣ > ∣ @ ∣ ^ ∣ |
来定义 let
或 and
运算符。
除非您专门尝试混淆您的代码,否则编写不带符号的单子代码非常容易,例如,如果我们从您的示例中删除过多的 1 括号,它将是已经很可读了,
let v0 =
Ok "one" >>= fun a ->
Ok "two" >>= fun c ->
print_endline a;
print_endline c;
Ok c
而且如果我们会使用let-binding操作符,例如使用monads [1,2]库(也是一个无耻的插件),那么我们可以写得更简洁,
open Monads.Std
open Monad.Result.Error.Syntax
open Monad.Result.Error.Let
let v1 =
let+ a = Ok "one" and+ b = Ok "two" in
print_endline a;
print_endline b;
b
1) OCaml 通过并列表示应用操作(函数对其参数的应用和构造函数对其参数的应用),例如,sin x
(不是sin(x)
),或Ok 42
(不是Ok (42)
),而且应用运算符比中缀运算符有更高的优先级(绑定更紧密),所以你可以写成sin x > cos x
。 lambda 运算符 fun <var> -> <expr>
与 monadic 运算符很好地链接,例如
x >>= (fun x -> y >>= (fun y -> x + y))
与
相同
x >>= fun x -> y >>= fun y -> x + y
或者,更多时候写成
x >>= fun x ->
y >>= fun y ->
x + y
作为对 lambda(抽象)运算符的 let-legacy 的致敬,cf.,
let* x = x in
let* y = y in
x + y
最新版本的 OCaml 甚至允许您对右侧进行双关,例如,
let* x in
let* y in
x + y
甚至
let* x and* y in
x + y
OCaml 有等同于 Haskell 的 Do Notation 吗?
另一种说法 - 有没有一种简单的方法可以更轻松地处理嵌套单子操作...因为这很烦人:
open Batteries
open BatResult.Infix
let () =
let out =
(Ok("one")) >>=
(fun a ->
let b = Ok("two") in
b >>= (fun c ->
print_endline(a);
print_endline(c);
Ok(c)
)) in
ignore(out)
是的,从 OCaml 4.08 开始,可以描述 let
个运算符。例如:
let (let*) x f = BatResult.bind x f
let (let+) x f = BatResult.map f x
这使得以接近于直接风格的风格编写程序成为可能:
let out =
let* a = Ok "one" in
let* b = Ok "two" in
let () = print_endline a in
let () = print_endline b in
Ok b
您可以描述大量运算符,对于单子(例如 let*
代表 bind
和 let+
代表 map
),对于应用(例如 let+
用于 map
和 and+
用于 product
(或 zip
))等等
否则可以使用语法扩展,例如https://github.com/janestreet/ppx_let which, for the moment, offers even more possibilities than the let operators. If you ever want examples of let operators, in Preface(不要脸的插件),我们定义了很多!
edit:如@ivg 所说,您可以使用任何 $ ∣ & ∣ * ∣ + ∣ - ∣ / ∣ = ∣ > ∣ @ ∣ ^ ∣ |
来定义 let
或 and
运算符。
除非您专门尝试混淆您的代码,否则编写不带符号的单子代码非常容易,例如,如果我们从您的示例中删除过多的 1 括号,它将是已经很可读了,
let v0 =
Ok "one" >>= fun a ->
Ok "two" >>= fun c ->
print_endline a;
print_endline c;
Ok c
而且如果我们会使用let-binding操作符,例如使用monads [1,2]库(也是一个无耻的插件),那么我们可以写得更简洁,
open Monads.Std
open Monad.Result.Error.Syntax
open Monad.Result.Error.Let
let v1 =
let+ a = Ok "one" and+ b = Ok "two" in
print_endline a;
print_endline b;
b
1) OCaml 通过并列表示应用操作(函数对其参数的应用和构造函数对其参数的应用),例如,sin x
(不是sin(x)
),或Ok 42
(不是Ok (42)
),而且应用运算符比中缀运算符有更高的优先级(绑定更紧密),所以你可以写成sin x > cos x
。 lambda 运算符 fun <var> -> <expr>
与 monadic 运算符很好地链接,例如
x >>= (fun x -> y >>= (fun y -> x + y))
与
相同x >>= fun x -> y >>= fun y -> x + y
或者,更多时候写成
x >>= fun x ->
y >>= fun y ->
x + y
作为对 lambda(抽象)运算符的 let-legacy 的致敬,cf.,
let* x = x in
let* y = y in
x + y
最新版本的 OCaml 甚至允许您对右侧进行双关,例如,
let* x in
let* y in
x + y
甚至
let* x and* y in
x + y