4 个版本
| 0.1.3 | 2021 年 1 月 8 日 |
|---|---|
| 0.1.2 | 2021 年 1 月 6 日 |
| 0.1.1 | 2021 年 1 月 6 日 |
| 0.1.0 | 2021 年 1 月 6 日 |
#495 在 数据结构
228 每月下载量
在 9 个 crate(5 个直接使用)中使用
13KB
160 行
do-notation,将单调 do 语法带到 Rust。
此 crate 提供了 m! 宏,它提供了 Haskell 单调语法糖 do。
注意:不能使用
do!语法,因为do是 Rust 的保留关键字。
语法与 Haskell 中的非常相似
- 您使用
m!宏;在 Haskell 中,您使用do关键字。 <-语法糖通过使用闭包 进入 右侧将左侧绑定到单调右侧。- 像 Rust 中几乎任何语句一样,您必须以分号(
;)结束您的语句。 - 最后一行必须不包含分号(
;)或包含return关键字。 - 您只能在最后一行使用
return。 - 只包含一个表达式和分号的行是有效的语句,其效果与
_ <- expr相同。 let绑定以let <pattern> = <expr>;的形式允许,并具有常规 Rust 的意义。
如何让我的单调与 m! 一起工作?
因为单调是高阶类型,所以无法以完全类型系统优雅的方式定义单调 do 语法。然而,此 crate 基于 Haskell 中的可重新绑定概念(即您可以更改 >>= 操作符的类型),因此 m! 有一个类型系统要求和一个语法要求。
首先,您需要实现一个特性:Lift,它允许将值 A 提升 到 A 的 单调结构。例如,将 A 提升到 Option 单调结构将得到 Option<A>。
然后,您需要提供一个 and_then 方法,它与 Haskell 的 >>= 操作符类似。选择使用 and_then 而不是像 flat_map 或 bind 这样的正确名称,是由于标准库的当前状态——像 Option 和 Result<_, E> 这样的单调没有定义 flat_map,但是有 and_then。类型签名没有被强制执行,但
and_then必须是一个二进制函数,它接受类型A、一个闭包A -> Monad<B>并返回Monad<B>,其中Monad是您为and_then添加的单调。例如,如果您为Option实现,则and_then接受一个A,一个闭包A -> Option<B>并返回一个Option<B>。and_then必须移动它的第一个参数,它必须是self。类型Self没有被强制执行。and_then的闭包必须接受一个具有FnOnce闭包的A。
<- 操作符的含义
<- 语法糖实际上不是一个操作符:它不是纯 Rust。相反,它是在 m! 中定义的一个技巧,允许同时使用 Lift::lift 和 and_then。当您查看 do-notation 块内的代码时,每个单调语句(在这个软件包中用 ; 分隔)可以想象为闭包中的一个新级别——确实是传递给 and_then 的闭包。
第一个例子:有错误的代码
人们最初学习的第一个单调应用之一是 有错误的 影响——Haskell 中的 Maybe。在 Rust 中,它是 Option。 Option 是一个有趣的单调,因为它允许您提前失败。
use do_notation::m;
let r = m! {
x <- Some("Hello, world!");
y <- Some(3);
Some(x.len() * y)
};
assert_eq!(r, Some(39));
binding <- expr 语法解开右侧部分并将其绑定到 binding,使其在后续调用中可用——记住,嵌套闭包。最后一行显式地重新进入结构(在这里,Option)。
请注意,可以在不指定结构如何或知道结构的情况下重新进入结构(使用 Option,你可以使用 Some 重新进入)。你可以使用 return 关键字,它将自动将值提升到正确的结构。
use do_notation::m;
let r = m! {
x <- Some(1);
y <- Some(2);
z <- Some(3);
return [x, y, z];
};
assert_eq!(r, Some([1, 2, 3]));