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数据结构

Download history 118/week @ 2024-03-15 219/week @ 2024-03-22 90/week @ 2024-03-29 91/week @ 2024-04-05 514/week @ 2024-04-12 676/week @ 2024-04-19 210/week @ 2024-04-26 207/week @ 2024-05-03 152/week @ 2024-05-10 452/week @ 2024-05-17 329/week @ 2024-05-24 77/week @ 2024-05-31 40/week @ 2024-06-07 56/week @ 2024-06-14 93/week @ 2024-06-21 25/week @ 2024-06-28

228 每月下载量
9 个 crate(5 个直接使用)中使用

BSD-3-Clause

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_mapbind 这样的正确名称,是由于标准库的当前状态——像 OptionResult<_, 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::liftand_then。当您查看 do-notation 块内的代码时,每个单调语句(在这个软件包中用 ; 分隔)可以想象为闭包中的一个新级别——确实是传递给 and_then 的闭包。

第一个例子:有错误的代码

人们最初学习的第一个单调应用之一是 有错误的 影响——Haskell 中的 Maybe。在 Rust 中,它是 OptionOption 是一个有趣的单调,因为它允许您提前失败。

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]));

无运行时依赖