有人告诉我,Rust 在仿射逻辑中有一种语义——所以它有删除/弱化但没有复制/收缩。
以下编译:
fn throw_away<A, B>(x: A, _y: B) -> A {
x
}
由于不允许重复,因此无法编译以下内容:
fn dup<A>(x: A) -> (A, A) {
(x, x)
}
同样,这些都不编译:
fn throw_away3<A, B>(x: A, f: fn(A) -> B) -> A {
x;
f(x)
}
fn throw_away4<A, B>(x: A, f: fn(A) -> B) -> A {
throw_away(x, f(x))
}
减弱也有目共睹
fn weaken<A, B, C>(f: fn(A) -> B) -> impl Fn(A, C) -> B {
move |x: A, y: C| f(x)
}
我们没有返回fn(A, C) -> B
,而是返回impl Fn(A, C) -> B
。有没有办法返回fn(A, C) -> B
呢?如果没有也没关系;我只是好奇。
我期望的另一件事是你可以提升A
到() -> A
. 但是,Rust 中的函数可以多次复制和使用。例如,
fn app_twice(f: fn(A) -> A, x: A) -> A {
f(f(x))
}
假设实际上有一个 function lift(x: A) -> fn() -> A
,那么我们可以打破 move 语义。例如,这将允许
fn dup_allowed(x: A) -> (A, A) {
let h = lift(x);
(h(), h())
}
因此要提升A
到fn() -> A
,我们需要知道该函数是“线性/仿射”或只能使用一次。Rust 为此提供了一种类型:FnOnce() -> A
. 在下文中,第一个编译,第二个不编译。
fn app_once(f: impl FnOnce(A) -> A, x: A) -> A {
f(x)
}
fn app_twice2(f: impl FnOnce(A) -> A, x: A) -> A {
f(f(x))
}
以下函数是互逆的(可能我不太了解 Rust 的语义,无法说它们实际上是互逆的):
fn lift_up<A>(x: A) -> impl FnOnce() -> A {
move || x
}
fn lift_up_r<A>(f: impl FnOnce() -> A) -> A {
f()
}
由于fn dup<A>(x: A) -> (A, A) { (x,x) }
无法编译,我认为以下可能是一个问题:
fn dup<A>(x: fn() -> A) -> (A, A) {
(x(), x())
}
似乎 Rust 正在为fn(A) -> B
类型做一些特别的事情。
为什么我不必在上面声明 x 是可重用/可复制的?
也许正在发生一些不同的事情。声明的函数有点特殊fn f(x: A) -> B { ... }
,就是特别的见证A -> B
。因此,如果f
需要多次使用,可以根据需要进行多次批评,但fn(A) -> B
完全不同:它不是构造的东西,而是假设的东西,并且必须使用fn(A) -> B
可复制的东西。事实上,我一直认为它更像是一个可自由复制的实体。这是我的粗略类比:
fn my_fun<A,B>(x :A) -> B { M }
“是” x:A |- M:Bfn(A) -> B
"is" !(A -o B) 因此可以自由复制- 因此
fn() -> A
“是” !(() -o A) = !A 因此fn () -> A
是 A 上的 (co)free 重复 fn dup_arg<A: Copy>(x: A) -> B { M }
“说” A 有重复或者是一个类固醇impl FnOnce (A) -> B
“是” A -o B
但这不可能是正确的......为了什么impl Fn(A) -> B
?从玩了一下,似乎fn(A) -> B
比 更严格Fn(A) -> B
。我错过了什么?