即使在使用类型投影后为 Either 声明 Functor 时出现编译错误
Compilation error when declaring Functor for Either even after using type projections
我正尝试在 Scala 中为 Either
编写一个 Functor
用于学术目的。在 higher-kinded
类型和 type-projections
的帮助下,我设法为 Either 编写了一个实现。
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
object Functor {
implicit def eitherFunctor[A] = new Functor[({type λ[α] = Either[A, α]})#λ] {
override def map[B, C](fa: Either[A, B])(f: B => C) = fa.map(f)
}
}
def mapAll[F[_], A, B](fa: F[A])(f: A => B)(implicit fe: Functor[F]): F[B] = fe.map(fa)(f)
val right: Either[String, Int] = Right(2)
mapAll(right)(_ + 2)
现在,上面的代码无法编译。我不确定原因,但我得到的编译错误在下面给出 -
Error:(19, 16) type mismatch;
found : Either[String,Int]
required: ?F[?A]
Note that implicit conversions are not applicable because they are ambiguous:
both method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A]
and method Ensuring in object Predef of type [A](self: A)Ensuring[A]
are possible conversion functions from Either[String,Int] to ?F[?A]
mapAll(right)(_ + 2)
谁能指出我在上面的代码中做错了什么?
PS:请不要建议我使用kind-projector
。
Either[+A, +B]
需要两个 类型参数 (如@Ziyang Liu 所说),因此对于您的示例实际上需要 BiFunctor
而不是 Functor
, BiFunctor
接受两个函子并绑定 两种类型 。
trait Bifunctor[F[_, _]] { self =>
////
/** `map` over both type parameters. */
def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D]
所以你可以像这样使用这个Bifunctor
:
Bifunctor[Either].bimap(Right(1): Either[String, Int])(_.toUpperCase, _ + 1).println
希望对您有所帮助。
正如其他人所说,编译器试图告诉您的是您的类型的形状不匹配。当你需要一个 F[_]
时,你需要一个带有单个类型参数的类型构造函数,Either[A, B]
不满足。
我们需要做的是在应用 mapAll
时应用类型 lambda,就像我们在创建 Either
仿函数的实例时所做的一样:
val right: Either[String, Int] = Right(2)
mapAll[({type λ[α]=Either[String, α]})#λ, Int, Int](right)(_ + 2)
我们现在压缩 String
并将其固定为第一个参数,允许类型投影类型只需要满足我们的 alpha,现在形状匹配。
当然,我们也可以使用类型别名,这将使我们在应用时无需指定任何额外的类型信息 mapAll
:
type MyEither[A] = Either[String, A]
val right: MyEither[Int] = Right(2)
mapAll(right)(_ + 2)
你刚刚被 SI-2712 咬了。如果您使用的是 Scala >= 2.12.2,只需将此行添加到您的 build.sbt
:
scalacOptions += "-Ypartial-unification"
对于其他 Scala 版本,您可以使用 this plugin。
我正尝试在 Scala 中为 Either
编写一个 Functor
用于学术目的。在 higher-kinded
类型和 type-projections
的帮助下,我设法为 Either 编写了一个实现。
trait Functor[F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
object Functor {
implicit def eitherFunctor[A] = new Functor[({type λ[α] = Either[A, α]})#λ] {
override def map[B, C](fa: Either[A, B])(f: B => C) = fa.map(f)
}
}
def mapAll[F[_], A, B](fa: F[A])(f: A => B)(implicit fe: Functor[F]): F[B] = fe.map(fa)(f)
val right: Either[String, Int] = Right(2)
mapAll(right)(_ + 2)
现在,上面的代码无法编译。我不确定原因,但我得到的编译错误在下面给出 -
Error:(19, 16) type mismatch;
found : Either[String,Int]
required: ?F[?A]
Note that implicit conversions are not applicable because they are ambiguous:
both method ArrowAssoc in object Predef of type [A](self: A)ArrowAssoc[A]
and method Ensuring in object Predef of type [A](self: A)Ensuring[A]
are possible conversion functions from Either[String,Int] to ?F[?A]
mapAll(right)(_ + 2)
谁能指出我在上面的代码中做错了什么?
PS:请不要建议我使用kind-projector
。
Either[+A, +B]
需要两个 类型参数 (如@Ziyang Liu 所说),因此对于您的示例实际上需要 BiFunctor
而不是 Functor
, BiFunctor
接受两个函子并绑定 两种类型 。
trait Bifunctor[F[_, _]] { self =>
////
/** `map` over both type parameters. */
def bimap[A, B, C, D](fab: F[A, B])(f: A => C, g: B => D): F[C, D]
所以你可以像这样使用这个Bifunctor
:
Bifunctor[Either].bimap(Right(1): Either[String, Int])(_.toUpperCase, _ + 1).println
希望对您有所帮助。
正如其他人所说,编译器试图告诉您的是您的类型的形状不匹配。当你需要一个 F[_]
时,你需要一个带有单个类型参数的类型构造函数,Either[A, B]
不满足。
我们需要做的是在应用 mapAll
时应用类型 lambda,就像我们在创建 Either
仿函数的实例时所做的一样:
val right: Either[String, Int] = Right(2)
mapAll[({type λ[α]=Either[String, α]})#λ, Int, Int](right)(_ + 2)
我们现在压缩 String
并将其固定为第一个参数,允许类型投影类型只需要满足我们的 alpha,现在形状匹配。
当然,我们也可以使用类型别名,这将使我们在应用时无需指定任何额外的类型信息 mapAll
:
type MyEither[A] = Either[String, A]
val right: MyEither[Int] = Right(2)
mapAll(right)(_ + 2)
你刚刚被 SI-2712 咬了。如果您使用的是 Scala >= 2.12.2,只需将此行添加到您的 build.sbt
:
scalacOptions += "-Ypartial-unification"
对于其他 Scala 版本,您可以使用 this plugin。