Scala 3 N 阶类型
可以跑的源码在这里 👉 https://github.com/jcouyang/meow
Scala 2
没有 Rank N Types, 所以我们需要使用 Cats 的 FunctionK 来做一些事情.
比如:
// forall a b c. (b, c) -> (a -> a) -> (b, c)
def rank[A,B,C](a: (B, C), doSomething: A => A): (B, C) = (doSomething(a._1), doSomething(a._2))
是编译不了的, 因为这只有 rank 1, 数 rank 几 很容易, 有几个forall, 这里只有一个, 也就是, A, B, C 是一个 rank.
同一个 rank 的毛病是, 编译器在看到 doSomething(a._1)
时, 由于 =a._1: B
时就决定了这时 doSomething: B => B
就
决定了 A = B, 再看后面的 doSomething(a._2)
编译就挂了, 因为我决定好了是 B 了你给我个 C 当然不行.
Scala 2 解决的办法可以通过 Cats 的 FunctionK:
def rank[B,C](a: (B, C), doSomething: Id ~> Id): (B, C) = (doSomething(a._1), doSomething(a._2))
可以看见 FunctionK 的小诡计把 A 从 rank[A, B, C
的类型参数上拿掉了, 也就是编译器完全不需要在编译这个函数的时候确定下来 doSomething
的
A 类型是啥.
使用 cats 也不是完全免费, 你在定义 doSomething
的时候要多些一堆代码
def rankNId: Id ~> Id = new (Id ~> Id) {
def apply[A](a: Id[A]): Id[A] = a
}
定义个 id 这么累, 你可以通过这个过程看到, 哦, 原来 A 类型被藏到这里了.
Scala 3
但是现在 Dotty 中, 已经实现了 Rank N Types, 叫 Polymorphic function types
// rank 2 type (forall a. a -> a)
val id = [T] => (t: T) => t
// forall b c. (b, c) -> (forall a. a -> a) -> (b, c)
def rank2[B,C](a: (B, C), doSomething: [T] => T => T): (B, C) = (doSomething(a._1), doSomething(a._2))
def main(args: Array[String]): Unit = {
println(
rank2((1, "2"), id)
)
}
是可以完美编译运行的.
不信? 可以自己在 scastie 上试试: https://scastie.scala-lang.org/jcouyang/3hNle3faQ7SpS4mCcoMSGA/29