我正在尝试将这个以n符号方式计算x^x的th 导数的程序移植到 Rust。这似乎很容易:
use std::rc::Rc;
type Expr = Rc<Expr2>;
enum Expr2 {
Int(i32),
Var(String),
Add(Expr, Expr),
Mul(Expr, Expr),
Pow(Expr, Expr),
Ln(Expr),
}
use Expr2::*;
fn pown(a: i32, b: i32) -> i32 {
match b {
0 => 1,
1 => a,
n => {
let b = pown(a, b / 2);
let b2 = b * b;
if n % 2 == 0 {
b2
} else {
b2 * a
}
}
}
}
fn add(f: Expr, g: Expr) -> Expr {
match (f, g) {
(Int(m), Int(n)) => Int(m + n),
(Int(0), f) => f,
(f, Int(n)) => add(Int(n), f),
(f, Add(Int(n), g)) => add(Int(n), add(f, g)),
(Add(f, g), h) => add(f, add(g, h)),
(f, g) => Add(f, g),
}
}
fn mul(f: Expr, g: Expr) -> Expr {
match (f, g) {
(Int(m), Int(n)) => Int(m * n),
(Int(0), f) => Int(0),
(Int(1), f) => f,
(f, Int(n)) => mul(Int(n), f),
(f, Mul(Int(n), g)) => mul(Int(n), mul(f, g)),
(Mul(f, g), h) => mul(f, mul(g, h)),
(f, g) => Mul(f, g),
}
}
fn pow(f: Expr, g: Expr) -> Expr {
match (f, g) {
(Int(m), Int(n)) => Int(pown(m, n)),
(f, Int(0)) => Int(1),
(f, Int(1)) => f,
(Int(0), f) => Int(1),
(f, g) => Pow(f, g),
}
}
fn ln(f: Expr) -> Expr {
match f {
Int(1) => Int(0),
f => Ln(f),
}
}
fn d(x: String, f: Expr) -> Expr {
match f {
Int(_) => Int(0),
Var(y) => if x == y {
x
} else {
y
},
Add(f, g) => add(d(x, f), d(x, g)),
Mul(f, g) => add(mul(f, d(x, g)), mul(g, d(x, f))),
Pow(f, g) => mul(
pow(f, g),
add(mul(mul(g, d(x, f)), pow(f, Int(-1))), mul(ln(f), d(x, g))),
),
Ln(f) => mul(d(x, f), pow(f, Int(-1))),
}
}
fn count(f: Expr) -> i32 {
match f {
Int(_) | Var(_) => 1,
Add(f, g) | Mul(f, g) | Pow(f, g) => count(f) + count(g),
Ln(f) => count(f),
}
}
fn string_of_expr(f: Expr) -> String {
count(f).to_string();
}
fn nest(n: i32, f: Expr, x: Expr) -> Expr {
if n == 0 {
x
} else {
nest(n - 1, f, f(x))
}
}
fn deriv(f: Expr) -> Expr {
let df = d("x", f);
format!("D({}) = {}", string_of_expr(f), string_of_expr(df));
df
}
fn main() {
let x = "x";
let f = pow(x, x);
// FIXME: Read command-line argument
let df = nest(9, deriv, f);
format!("{}", count(df));
}
Run Code Online (Sandbox Code Playgroud)
该类型需要转换为enumRust 中计数的引用,并且模式匹配可以生成非常相似的代码,除了......它不起作用。据我所知,Rust 中的模式无法匹配取消引用Rc. 所以,无论我做什么,它都会在嵌套模式上失败,比如(f, Add(Int(n), g)).
我是否遗漏了什么,或者嵌套模式真的不可能匹配 Rust 中的递归数据类型?显然,有一种叫做“框语法”的东西可以在已经在绘图板上使用四年的模式(除其他外)中取消引用。
看来是的,目前不可能做到这一点。递归数据类型需要间接,例如Rc。与嵌套模式匹配时,间接需要取消引用。如今,Rust 中无法在模式匹配内取消引用。
解决方法是手动编译您的模式,即就好像您只有 C-style 一样switch。
自 2014 年以来就一直在讨论一种名为“盒子模式”的功能,该功能可能会在未来解决这个问题,但尚未发布。
| 归档时间: |
|
| 查看次数: |
1397 次 |
| 最近记录: |