Scala中具有两个参数的类型构造函数的函数实例

问题描述 投票:5回答:2

我有一个带有两个参数的类Foo,我正在尝试为Foo编写一个Functor实例,并修复了第一个参数,如下所示:

object Scratchpad {

  trait Functor[F[_]] {
    def fmap[A, B](f: A => B): F[A] => F[B]
  }

  case class Foo[X, Y](value: Y)

  implicit def fooInstances[X]: Functor[Foo[X, _]] =
    new Functor[Foo[X, _]] {
      def fmap[A, B](f: A => B): Foo[X, A] => Foo[X, B] =
        foo => Foo[X, B](f(foo.value))
    }
}

但上面的代码无法编译,生成以下错误:

Error:(9, 41) Scratchpad.Foo[X, _] takes no type parameters, expected: one
  implicit def fooInstances[X]: Functor[Foo[X, _]] =

我知道Scalaz使用他们的\/类型执行类似的操作,但检查他们的源代码会显示奇怪的?,它不能为我编译:

implicit def DisjunctionInstances1[L]: Traverse[L \/ ?] with Monad[L \/ ?] with BindRec[L \/ ?] with Cozip[L \/ ?] with Plus[L \/ ?] with Optional[L \/ ?] with MonadError[L \/ ?, L] =

Scalaz ?如何工作,如何为Foo编写Functor实例?

scala typeclass scalaz kind-projector
2个回答
6
投票

您正在寻找部分应用类型级构造函数。不幸的是,我们不能直接这样做。但是,我们仍然可以使用一个名为Structural Types的小功能间接地这样做。为了将Foo从双参数类型构造函数转换为单参数类型构造函数,我们将在匿名结构类型中定义类型同义词。

implicit def fooInstances[X]: Functor[({ type T[A] = Foo[X, A] })#T] =
  new Functor[({ type T[A] = Foo[X, A] })#T] {
    // ...
  }

类型上下文中的大括号{}定义了一个匿名类型,我们正在利用它来在类型级别创建一个lambda函数。我们定义一个带有别名的匿名类型,然后立即评估该别名。


7
投票

但检查他们的源代码会显示一个奇怪的?,这对我来说无法编译

?来自kind-projector项目,这是一个Scala编译器插件,你需要添加到你的build.sbt

resolvers += Resolver.sonatypeRepo("releases")

addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.4")

这会为你创造类型lambdas:

implicit def fooInstances[X]: Functor[Foo[X, ?]] =
  new Functor[Foo[X, ?]] {
    def fmap[A, B](f: A => B): Foo[X, A] => Foo[X, B] =
      foo => Foo[X, B](f(foo.value))
}

请记住,我们也可以使用类型别名的部分类型应用程序:

implicit def fooInstances[X] = {
  type PartiallyAppliedFoo[A] = Foo[X, A]
  new Functor[PartiallyAppliedFoo] {
    override def fmap[A, B](f: (A) => B): (PartiallyAppliedFoo[A]) => PartiallyAppliedFoo[B] = foo => Foo[X, B](f(foo.value))
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.