在 scala 中具有两个参数的类型构造函数的函子实例



我有一个带有两个参数的类Foo,我正在尝试为Foo编写一个固定第一个参数的函子实例,如下所示:

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编写函子实例?

但检查他们的源代码会发现一个奇怪的?,它没有 为我编译

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

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(

请注意,对于部分应用的类型,kind 项目的语法已从?更改为*,因此上面的示例应该是:

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))
}

您希望部分应用类型级构造函数。不幸的是,我们不能直接做到这一点。但是,我们仍然可以使用称为结构类型的小功能间接执行此操作。为了将Foo从双参数类型构造函数转换为单参数类型构造函数,我们将在匿名结构类型中定义一个类型同义词。

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

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

相关内容

  • 没有找到相关文章

最新更新