我有一个带有两个参数的类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实例?
答案 0 :(得分:7)
但检查他们的源代码会显示一个奇怪的?,但事实并非如此 为我编译
?
来自kind-projector
项目,该项目是您需要添加到build.sbt
的Scala编译器插件:
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))
}
}
答案 1 :(得分:6)
您正在寻找部分应用类型级构造函数。不幸的是,我们无法直接这样做。但是,我们仍然可以使用名为Structural Types的小功能间接地这样做。为了将public class IngAdapter extends ArrayAdapter<Ing> {
IngAdapter(Context context, ArrayList<Ing> ings) {
Ing tomatoSauce = new Ing("Tomato Sauce", 0 ,0);
Ing chicken = new Ing("Chicken", 0 ,0);
Ing olives = new Ing("Olives", 0, 0);
ings.add(tomatoSauce);
ings.add(chicken);
ings.add(olives);
super(context, 0, ings);
}
}
从双参数类型构造函数转换为单参数类型构造函数,我们将在匿名结构类型中定义类型同义词。
Foo
类型上下文中的大括号implicit def fooInstances[X]: Functor[({ type T[A] = Foo[X, A] })#T] =
new Functor[({ type T[A] = Foo[X, A] })#T] {
// ...
}
定义了一个匿名类型,我们正在利用它来在类型级别创建一个lambda函数。我们定义一个带有别名的匿名类型,然后立即评估该别名。