scala 使用匿名函数创建FunctionK示例

rwqw0loc  于 5个月前  发布在  Scala
关注(0)|答案(2)|浏览(61)

我想创建一个带有匿名函数的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-RC1cats.core==2.10.0编译

uqcuzwp8

uqcuzwp81#

让我们一步一步来分析。
FunctionK实际上不是一个函数。在Scala 3中,它可以定义为:

type FunctionK[F[_], G[_]] = [A] => F[A] => G[A]

字符串
这将使它成为polymorphic function type。但它是在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


我们正在使用单一抽象方法语法-编译器看到我们正在使用lambda语法,我们可以使用new FunctionLike[Int, String] { ... },但它也看到这个trait/abstract class只有一个抽象方法,所以它可以假设我们想要通过实现这个方法来实现整个trait/abstract class(所以我们可以 * 假装 * 它是一个函数)。
问题是,SAM目前似乎只对普通(单态)方法实现,当你对多态方法使用Rolldas时,它不会建立连接:

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) => ...- type parameters have to be explicitly defined and explicitly used in one of the arguments.

  • Gaël的答案解释了如何实际实现它。*
v7pvogib

v7pvogib2#

实际上,在这种情况下,编译器不能自动推断类型。
你必须使用verbose语法:

import cats.~>

given (Option ~> List) = new ~>[Option, List] {
  def apply[A](o: Option[A]): List[A] = o match {
    case Some(a) => a :: Nil
    case None => Nil
  }
}

字符串

  • Mateusz的回答很好地解释了为什么:)*

相关问题