我将尝试解释更多细节:
为什么 scalaz.Validation[scalaz.NonEmptyList[_ <: String],Int] 这不能与 |@| 一起使用?
isEven(4) |@| isEven(6) ...
首先,isEven(4) 尝试使用|@| 运算符将implicitly 类型从Validation[+E, +A] 类型转换为ApplyOps[F0.M,F0.A]type。作为ApplySyntax中的implicit方法:
implicit def ToApplyOpsUnapply[FA](v: FA)(implicit F0: Unapply[Apply, FA]) =
new ApplyOps[F0.M,F0.A](F0(v))(F0.TC)
如上面的代码,对于这个implicit的转换,我们还需要一个隐式 F0: Unapply[Apply, FA]变量。对于UnApplyimplicits,它在UnApply:
implicit def unapplyMFA[TC[_[_]], M0[_[_], _], F0[_], A0](implicit TC0: TC[M0[F0, ?]]): Unapply[TC, M0[F0, A0]] {
type M[X] = M0[F0, X]
type A = A0
} =
new Unapply[TC, M0[F0, A0]] {
type M[X] = M0[F0, X]
type A = A0
def TC = TC0
def leibniz = refl
}
作为Validation 类型,它使用unapplyMFA implicits 变量。在那里,我们还发现它正在寻找另一个 implicits TC0: TC[M0[F0, ?]] 变量。与之前的ToApplyOpsUnapply 一样,其中TC0 将是Apply 类型,也可以是Applicative 类型。所以它会尝试寻找Validation 到Applicative implicits,它在Validation.scala
implicit def ValidationApplicative[L: Semigroup]: Applicative[Validation[L, ?]] =
new Applicative[Validation[L, ?]] {
override def map[A, B](fa: Validation[L, A])(f: A => B) =
fa map f
def point[A](a: => A) =
Success(a)
def ap[A, B](fa: => Validation[L, A])(f: => Validation[L, A => B]) =
fa ap f
}
对于Semigroup 的定义:
trait Semigroup[F] { self => //F is invariant, unlike Option[+A]
所以问题是:F 是 type invariant,不像 Option[+A],编译器找不到适合该类型 Validaiton 的 Applicative 隐式.
有一个关于如何为此启用类型变体的小演示:
def isEven(x: Int): Validation[NonEmptyList[_ <: String], Int] =
if (x % 2 == 0) x.successNel else "not even".failureNel
val res: String = foo(isEven(4))
def foo[FA](v: FA)(implicit F0: Unapply[Apply, FA]): String = "foo bar"
implicit def ValidationApplicative[L]: Applicative[Validation[L, ?]] =
new Applicative[Validation[L, ?]] {
override def map[A, B](fa: Validation[L, A])(f: A => B) =
fa map f
def point[A](a: => A) =
Success(a)
def ap[A, B](fa: => Validation[L, A])(f: => Validation[L, A => B]) =
//fa ap f
null
}
在那里,我们只是从Semigroup unbind L,所以现在这是类型变体。只是为了好玩;)。