魔法师の高塔

Rust学习 3

我十分喜欢用一个例子来帮助理解Monad这个概念。

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
enum Expr {
Num(i32),
Neg(Box<Expr>),
Add(Box<Expr>,Box<Expr>),
Div(Box<Expr>,Box<Expr>)
}
impl Expr{
fn eval(&self) -> Option<i32>{
match *self {
Expr::Num(a) => Some(a),
Expr::Neg(ref a) => {
match a.eval() {
Some(aa) => Some(0 - aa),
_ => None
}
},
Expr::Add(ref a,ref b) => {
match a.eval() {
Some(aa) => {
match b.eval() {
Some(bb) => Some(aa+bb),
_ => None
}
},
_ => None
}
},
Expr::Div(ref a,ref b) => {
match b.eval() {
Some(0) | None => None,
Some(bb) => {
match a.eval() {
Some(aa) => Some(aa/bb),
_ => None
}
}
}
}
}
}
}
fn main() {
let a: Expr = Expr::Num(5);
}

这种写法冗长,令人痛苦的。如果我们细细观察,一定可以发现,如果一个Expreval函数有值的话,这个值会在下面的计算中包装进Option,我们可以将这个计算抽象为i32 -> (i32 -> Option<i32>) -> Option<i32>,显然,Rust已经为我们准备好了这个函数,and_then,名字非常恰当。
另,补全,准备下一章为这个写个解析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
enum Expr {
Num(i32),
Neg(Box<Expr>),
Add(Box<Expr>,Box<Expr>),
Sub(Box<Expr>,Box<Expr>),
Mul(Box<Expr>,Box<Expr>),
Div(Box<Expr>,Box<Expr>)
}
impl Expr {
fn eval(&self) -> Option<i32> {
match *self {
Expr::Num(a) => Some(a),
Expr::Neg(ref a) => a.eval().and_then(|x|Some(-x)),
Expr::Add(ref a, ref b) => a.eval().and_then(|x|b.eval().and_then(|y|Some(x+y))),
Expr::Sub(ref a, ref b) => a.eval().and_then(|x|b.eval().and_then(|y|Some(x-y))),
Expr::Mul(ref a, ref b) => a.eval().and_then(|x|b.eval().and_then(|y|Some(x*y))),
Expr::Div(ref a, ref b) => a.eval().and_then(|x|b.eval().and_then(|y|
match y {
0 => None,
_ => Some(x/y)
}
))
}
}
}
fn main() {
let a: Expr = Expr::Num(0);
let b: Expr = Expr::Num(12);
let c: Expr = Expr::Div(Box::new(b),Box::new(a));
let d: Expr = Expr::Num(8);
let e: Expr = Expr::Div(Box::new(d),Box::new(c));
println!("{:?}", e.eval().ok_or("Error"));
}

优雅。