Scala 是否支持类型构造函数的部分应用?
Does Scala support partial application of type constructors?
我正在从 scala-exercises 学习猫。
想知道如何使用高阶类型,有一些尝试:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
def someThingFail1[In]() = new Functor[Function1[In, _]] {
override def map[A, B](fa: Function1[In, A])(f: A => B): Function1[In, B] = ???
}
def someThingFail2[In]() = new Functor[Either[In, _]] {
override def map[A, B](fa: Either[In, A])(f: A => B): Either[In, B] = ???
}
def someThingFail3() = new Functor[List[_]] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
//only this one can compile
def someThingRight1() = new Functor[List] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
前三个函数无法编译,错误信息如下:
[error] /Users/lorancechen/version_control_project/_tutorials/learn-cats/src/main/scala/mycats/Main.scala:16:42: Either[In, _] takes no type parameters, expected: one
[error] def someThingFail2[In]() = new Functor[Either[In, _]] {
[error] ^
为什么 Scala 不支持 type hole? Dotty 编译器会支持吗?谢谢
那是因为
Either[X, _]
是存在类型,可以显式写成
Either[X, Y] forSome { type Y }
这有点类似于 Java 的通配符,而不是您想要作为高阶 Functor
类型构造函数的参数。您想要的是 类型的 lambda。本来可以这么写的:
({type lam[Y] = Either[X, Y]})#lam
lambda 类型完全可以在 Scala 中使用这一事实并不是计划中的功能,而是一个 accidental discovery, and the syntax was somewhat lengthy. However, there is the non/kind-projector 插件可以显着简化它。使用此插件,您的代码将变为:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
def someThingFail1[In]() = new Functor[Function1[In, ?]] {
override def map[A, B](fa: Function1[In, A])(f: A => B): Function1[In, B] = ???
}
def someThingFail2[In]() = new Functor[Either[In, ?]] {
override def map[A, B](fa: Either[In, A])(f: A => B): Either[In, B] = ???
}
def someThingFail3() = new Functor[List[?]] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
//only this one can compile
def someThingRight1() = new Functor[List] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
(使用 scala 2.12.4、cats 1.0.1、kind-projector 0.9.4 测试)。
注意这个插件is used in cats source code(搜索?
)。
一切都会在dotty变得更好,它already supports a neat syntax for type lambdas。
我正在从 scala-exercises 学习猫。
想知道如何使用高阶类型,有一些尝试:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
def someThingFail1[In]() = new Functor[Function1[In, _]] {
override def map[A, B](fa: Function1[In, A])(f: A => B): Function1[In, B] = ???
}
def someThingFail2[In]() = new Functor[Either[In, _]] {
override def map[A, B](fa: Either[In, A])(f: A => B): Either[In, B] = ???
}
def someThingFail3() = new Functor[List[_]] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
//only this one can compile
def someThingRight1() = new Functor[List] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
前三个函数无法编译,错误信息如下:
[error] /Users/lorancechen/version_control_project/_tutorials/learn-cats/src/main/scala/mycats/Main.scala:16:42: Either[In, _] takes no type parameters, expected: one
[error] def someThingFail2[In]() = new Functor[Either[In, _]] {
[error] ^
为什么 Scala 不支持 type hole? Dotty 编译器会支持吗?谢谢
那是因为
Either[X, _]
是存在类型,可以显式写成
Either[X, Y] forSome { type Y }
这有点类似于 Java 的通配符,而不是您想要作为高阶 Functor
类型构造函数的参数。您想要的是 类型的 lambda。本来可以这么写的:
({type lam[Y] = Either[X, Y]})#lam
lambda 类型完全可以在 Scala 中使用这一事实并不是计划中的功能,而是一个 accidental discovery, and the syntax was somewhat lengthy. However, there is the non/kind-projector 插件可以显着简化它。使用此插件,您的代码将变为:
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
def someThingFail1[In]() = new Functor[Function1[In, ?]] {
override def map[A, B](fa: Function1[In, A])(f: A => B): Function1[In, B] = ???
}
def someThingFail2[In]() = new Functor[Either[In, ?]] {
override def map[A, B](fa: Either[In, A])(f: A => B): Either[In, B] = ???
}
def someThingFail3() = new Functor[List[?]] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
//only this one can compile
def someThingRight1() = new Functor[List] {
override def map[A, B](fa: List[A])(f: A => B): List[B] = ???
}
(使用 scala 2.12.4、cats 1.0.1、kind-projector 0.9.4 测试)。
注意这个插件is used in cats source code(搜索?
)。
一切都会在dotty变得更好,它already supports a neat syntax for type lambdas。