【发布时间】:2020-12-11 08:06:37
【问题描述】:
我试图在 Dotty 中使用匹配类型实现 SKI combinator calculus。
SKI 组合子演算的简要说明:
-
S、K和I是术语 -
(xy)是一个术语,如果x和y是术语并且类似于函数应用程序 -
(((Sx)y)z)(与Sxyz相同)返回xz(yz)(与(xz)(yz)相同) -
((Kx)y)(与Kxy相同)返回x -
(Ix)返回x
以下是我使用的(R 尽可能减少该术语)。术语(xy) 写为元组(x,y),S、K 和I 是特征。
trait S
trait K
trait I
type R[T] = T match {
case (((S,x),y),z) => R[((x,z),(y,z))]
case ((K,x),y) => R[x]
case (I,x) => R[x]
case (a,b) => R[a] match {
case `a` => (a, R[b])
case _ => R[(R[a], R[b])]
}
case T => T
}
但是,以下 2 行无法编译(出于相同的原因)(Scastie):
val check: (K, K) = ??? : R[(((S,I),I),K)]
val check2: (K, K) = ??? : R[((I,K),(I,K))]
错误说它需要(K,K),但找到了R[((I, K), (I, K))]。我希望它首先看到 S 并将其转换为 (IK)(IK) 或 R[((I,K),(I,K))],然后它应该匹配第一个 (I, K) 的评估并看到它是 K,这与 @987654354 不同@,让它返回R[(R[(I,K)], R[(I,K)])],变成R[(K,K)],变成(K,K)。
但是,它不超出R[((I,K),(I,K))]。显然,如果它是嵌套的,它不会减少术语。这很奇怪,因为我尝试了相同的方法,但使用了一个实际的运行时函数,而且它似乎可以正常工作 (Scastie)。
case object S
case object K
case object I
def r(t: Any): Any = t match {
case (((S,x),y),z) => r(((x,z),(y,z)))
case ((K,x),y) => r(x)
case (I,x) => r(x)
case (a,b) => r(a) match {
case `a` => (a, r(b))
case c => (c, r(b))
}
case _ => t
}
println(r((((S, I), I), K))) 的输出是 (K,K),正如预期的那样。
有趣的是,删除K 的规则可以让它编译,但它不会将(K, K) 和R[(K, K)] 识别为同一类型。也许这就是导致问题的原因? (Scastie)
def check2: (K, K) = ??? : R[(K, K)]
//Found: R[(K, K)]
//Required: (K, K)
【问题讨论】:
标签: scala pattern-matching scala-3 dotty match-types