9

Scala 3 N 阶类型

 3 years ago
source link: https://blog.oyanglul.us/scala/dotty/rank-n-type
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Scala 3 N 阶类型

Scala 3 N 阶类型

Table of Contents


可以跑的源码在这里 👉 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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK