注:我将SI的定义如下:https://en.wikipedia.org/wiki/SKI_combinator_calculus#Informal_description

所以S xyz = xz(yz),或者说在铁 rust :

fn s <Z, Y, X> (
    x: fn(Z) -> fn(Y) -> X,
    y: fn(Z) -> Y,
    z: Z
) -> X
where Z: Copy
{
    x(z)(y(z))
}

让我们再定义一个辅助I x = x:

fn i <X> (x: X) -> X { x }

我知道S I I xx(x)(我实际上试图解决的问题是找到一种x类型,使x适用于它自己),但让我们不要成为通用的RN,而是try 使用S I I I.

显然,S I I I = I(I)(I(I)) = I(I) = I

let _ = s(i, i, i); // = i(i)(i(i)) = i(i) = i

这在我看来是合法的,但在编译器的眼中是不合法的:

error[E0308]: mismatched types
  --> src/main.rs:45:18
   |
45 |     let _ = s(i, i, i);
   |             -    ^ cyclic type of infinite size
   |             |
   |             arguments to this function are incorrect
   |
note: function defined here
  --> src/main.rs:32:4
   |
32 | fn s <Z, Y, X> (
   |    ^
33 |     x: fn(Z) -> fn(Y) -> X,
34 |     y: fn(Z) -> Y,
   |     -------------

我找到了一个"解释",这个错误之所以会发生,是因为rustc无法处理某些无法计算的类型.有道理,但我在这里看不到任何上述类型的样本.你能告诉我它发生在哪里吗(如果可能的话,还有如何解决它)?

推荐答案

让我们试着写下Rust必须解决的类型方程,以了解哪里出了问题.每个i具有对应于给定X的类型fn(X) -> X.因为它们可以为每i个单独 Select ,所以我将它们命名为X₁X₂X₃.

  1. 第一个i的类型是fn(X₁) -> X₁,预期的类型是fn(Z) -> fn(Y) -> X,因此统一后我们有Z = X₁ = fn(Y) -> X(1).
  2. 第二个i的类型是fn(X₂) -> X₂,而预期的类型是fn(Z) -> Y,因此统一后我们有Z = X₂ = Y(2).
  3. 第三类方程是X₃ = Z(3).

把(1)和(2)加起来,就是Y = fn(Y) -> X.这个类型等式是循环的:您永远找不到一个有限类型(至少在Rust的类型系统中)可以满足这一点.

顺便说一句,OCaml可以打字判断if you explicitely turn on recursive types with 100:

# let s x y z = x z (y z) in s Fun.id Fun.id Fun.id;;
- : 'a -> 'a as 'a = <fun>
#

如果你正在研究lambda演算,朋友们,OCaml可能是一个更好的 Select .

至于Rust,我不认为有任何类型友好的方法可以做到这一点.

Rust相关问答推荐

移植带有可变borrow 的C代码-卸载期间错误(nappgui示例)

Rust kill std::processs::child

如何将`Join_all``Vec<;Result<;Vec<;Foo&>;,Anywhere::Error&>;`合并到`Result<;Vec<;Foo&>;,Anywhere::Error&>;`

当第二个`let`依赖于第一个`let()`时,如何在一行中有多个`let()`?

"value is never read警告似乎不正确.我应该忽略它吗?

有没有办法避免在While循环中多次borrow `*分支`

使用极点数据帧时,找不到枚举结果的方法lazy()

字段类型为Boxed的 struct 的生存期必须超过static

在文件链实施中绕过borrow 判断器

通过异常从同步代码中产生yield 是如何工作的?

带引脚和不带引脚的比较功能

tokio::spawn 有和没有异步块

更新 rust ndarray 中矩阵的一行

如何保存指向持有引用数据的指针?

Rust并发读写引起的死锁问题

在 Bevy 项目中为 TextureAtlas 精灵实施 NearestNeighbor 的正确方法是什么?

如何获得对数组子集的工作可变引用?

Rust 中的let是做什么的?

实现不消费的迭代器

为什么我不能为 Display+Debug 的泛型类型实现 std::error::Error 但有一个不是泛型参数的类型?