Scala 中具有两个参数的类型构造函数的函子实例
Functor Instance for Type Constructor with Two Parameters in Scala
我有一个带有两个参数的class 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 实例?
您希望部分应用类型级构造函数。不幸的是,我们不能直接这样做。但是,我们仍然可以使用一个名为 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 函数。我们在其中定义一个带有别名的匿名类型,然后立即评估该别名。
but inspection of their source code reveals an odd ?, which doesn't
compile for me
?
来自 kind-projector
项目,这是一个 Scala 编译器插件,你需要添加到你的 build.sbt
:
resolvers += Resolver.sonatypeRepo("releases")
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.4")
它为您美化了 lambda 类型的创建:
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))
}
}
编辑 (05/04/2020)
请注意,对于部分应用的类型,种类项目的语法已从 ?
更改为 *
,因此上面的示例应为:
sbt:
resolvers += Resolver.sonatypeRepo("releases")
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.11.0")
代码:
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))
}
我有一个带有两个参数的class 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 实例?
您希望部分应用类型级构造函数。不幸的是,我们不能直接这样做。但是,我们仍然可以使用一个名为 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 函数。我们在其中定义一个带有别名的匿名类型,然后立即评估该别名。
but inspection of their source code reveals an odd ?, which doesn't compile for me
?
来自 kind-projector
项目,这是一个 Scala 编译器插件,你需要添加到你的 build.sbt
:
resolvers += Resolver.sonatypeRepo("releases")
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.9.4")
它为您美化了 lambda 类型的创建:
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))
}
}
编辑 (05/04/2020)
请注意,对于部分应用的类型,种类项目的语法已从 ?
更改为 *
,因此上面的示例应为:
sbt:
resolvers += Resolver.sonatypeRepo("releases")
addCompilerPlugin("org.spire-math" %% "kind-projector" % "0.11.0")
代码:
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))
}