这个问题是关于 Scala 隐式解析系统的限制,我在使用 Scalaz 时遇到过几次,这对我来说没有多大意义。我已将问题提炼为下面的无 Scalaz 版本,但如果需要,我很乐意提供有关动机的更多信息。
假设我有几个类型类见证了类型构造函数:
import scala.language.higherKinds
trait Foo[F[_]]
trait Bar[F[_], A]
现在还假设如果我有Foo
一些实例F
,我知道我也有一个Foo
实例Bar[F, _]
:
implicit def barFoo[F[_]: Foo] = new Foo[({type L[X] = Bar[F, X]})#L] {}
我也有实例List
和右侧Either
:
implicit object listFoo extends Foo[List]
implicit def eitherFoo[A] = new Foo[({type L[X] = Either[A, X]})#L] {}
现在很清楚我应该能够编写以下内容:
type BarList[X] = Bar[List, X]
implicitly[Foo[BarList]]
或者,等效地:
implicitly[Foo[({type L[X] = Bar[List, X]})#L]]
事实上,两者都按预期工作。
所以我尝试以下方法:
type StringOr[X] = Either[String, X]
type BarStringOr[X] = Bar[StringOr, X]
接着:
scala> implicitly[Foo[BarStringOr]]
res2: Foo[BarStringOr] = $anon$1@39a6c855
同样,这里没有惊喜。但后来我尝试:
implicitly[Foo[({type L[X] = Bar[StringOr, X]})#L]]
我得到以下信息:
<console>:15: error: could not find implicit value for parameter e: Foo[[X]Bar[[X]scala.util.Either[String,X],X]]
implicitly[Foo[({type L[X] = Bar[StringOr, X]})#L]]
^
请注意,我可以毫无问题地推断出必要的Foo
实例StringOr
,或者显式调用barFoo
以获取所需的实例:
scala> implicitly[Foo[StringOr]]
res4: Foo[StringOr] = $anon$1@3eaac006
scala> barFoo[StringOr]
res5: Foo[[X]Bar[StringOr,X]] = $anon$1@179fbfea
我无法确定允许 lambda 类型版本适用于前者但不适用于后者的情况List
之间可能存在的重要区别。StringOr
我在 Scala 2.10.0-RC5 和 2.9.2 上试过这个。在整个过程中添加协方差并没有帮助。
我错过了一些明显的东西吗?有人可以指出规范中的某些内容可以帮助我理解这一点,或者指向以前对类似问题的讨论吗?