我想创建一个具有匿名函数的
FunctionK
实例。这是最小的例子:
import cats.~>
given (Option ~> List) = {
case Some(a) => a :: Nil
case None => Nil
}
但是,此代码片段会引发编译错误:
Missing parameter type
I could not infer the type of the parameter x$1
in expanded function:
x$1 =>
x$1 match
{
case Some(a) =>
a :: Nil
case None =>
Nil
}
Expected type for the whole anonymous function:
cats.arrow.FunctionK[Option, List]
编译器不够智能,无法推断所有类型,还是我使用匿名函数的方式不正确?
由
Scala==3.4.0-RC1
和 cats.core==2.10.0
编译
我们来一步步分析吧。
FunctionK
实际上不是一个函数。在仅限 Scala 3 的世界中,它可以定义为:
type FunctionK[F[_], G[_]] = [A] => F[A] => F[G]
这将使其成为多态函数类型。但它是在 Scala 3 成为现实之前定义的,并且需要与旧的表示向后兼容,它:
trait FunctionK[F[_], G[_]] {
def apply[A](fa: F[A]): G[A]
}
这是 Scala 2 针对没有多态函数类型的解决方法。
在以下情况下:
trait FunctionLike[A, B] {
def method(a: A): B
}
val fl: FunctionLike[Int, String] = _.toString
我们正在使用单一抽象方法语法 - 编译器发现我们在可以使用
new FunctionLike[Int, String] { ... }
的地方使用 lambda 语法,但它也看到这个 trait
/abstract class
只有 1 个抽象方法,因此它可以假设我们想通过实现这个方法来实现整个trait
/abstract class
。
事实是,SAM 目前似乎仅针对普通(单态)方法实现,当您将 lambda 用于多态方法时,它不会建立连接:
import cats.~>
given (Option ~> List) = [A] => (opt: Option[A]) => opt match {
case Some(a) => a :: Nil
case None => Nil
}
// error:
// Found: [A] => (opt: Option[A]) => List[A]
// Required: cats.arrow.FunctionK[Option, List]
在您的情况下,您还使用了单态函数类型的语法:当前,当您需要多态函数类型时,您必须编写:
[A] => (a: A) => ...
- 类型参数必须显式定义并在参数之一中显式使用。