类型别名和类型lambdas之间的区别

Tra*_*own 12 types scala scalaz implicits

这个问题是关于Scala的隐式解析系统的局限性,我在使用Scalaz时遇到过几次,这对我来说没有多大意义.我已将问题提炼到下面的Scalaz-less版本,但如果需要,我很乐意提供有关动机的更多信息.

假设我有几个类型类见证了类型构造函数:

import scala.language.higherKinds

trait Foo[F[_]]
trait Bar[F[_], A]
Run Code Online (Sandbox Code Playgroud)

现在也假设如果我有一个Foo实例F,我知道我也有一个Foo实例Bar[F, _]:

implicit def barFoo[F[_]: Foo] = new Foo[({type L[X] = Bar[F, X]})#L] {}
Run Code Online (Sandbox Code Playgroud)

我也有实例List和右边Either:

implicit object listFoo extends Foo[List]
implicit def eitherFoo[A] = new Foo[({type L[X] = Either[A, X]})#L] {}
Run Code Online (Sandbox Code Playgroud)

现在很明显我应该能够编写以下内容:

type BarList[X] = Bar[List, X]

implicitly[Foo[BarList]]
Run Code Online (Sandbox Code Playgroud)

或者,等效地:

implicitly[Foo[({type L[X] = Bar[List, X]})#L]]
Run Code Online (Sandbox Code Playgroud)

事实上,两者都完全符合预期.

所以我尝试以下方法:

type StringOr[X] = Either[String, X]
type BarStringOr[X] = Bar[StringOr, X]
Run Code Online (Sandbox Code Playgroud)

然后:

scala> implicitly[Foo[BarStringOr]]
res2: Foo[BarStringOr] = $anon$1@39a6c855
Run Code Online (Sandbox Code Playgroud)

再次,这里没有惊喜.但后来我尝试:

implicitly[Foo[({type L[X] = Bar[StringOr, X]})#L]]
Run Code Online (Sandbox Code Playgroud)

我得到以下内容:

<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]]
                        ^
Run Code Online (Sandbox Code Playgroud)

请注意,我没有问题推断必要的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
Run Code Online (Sandbox Code Playgroud)

我无法确定允许类型lambda版本为前者而不是后者工作的案例ListStringOr案例之间可能存在哪些重要区别.

我在Scala 2.10.0-RC5和2.9.2上尝试过这个.在整个过程中添加协方差无济于事.

我错过了一些明显的东西吗 有人能指出我在规范中的某些内容可以帮助我理解这一点,或者之前对类似问题的讨论吗?

Owe*_*wen 4

好吧,我不是 100% 确定,但我认为我们可以通过将其减少到最简单的失败情况来取得一些进展。隐式不是这里的问题,类型别名也不是。这足以失败:

trait Foo[F[_]]
trait Bar[F[_], A]

def barFoo[F[_]: Foo] = new Foo[({type L[X] = Bar[F, X]})#L] {}

val res1: Foo[({type L[X] = Either[String, X]})#L] = null

val works = barFoo[({type L[X] = Either[String, X]})#L](res1)
val fails = barFoo(res1)
Run Code Online (Sandbox Code Playgroud)

问题在于 Scala 无法推断 as 的类型barFoo参数[X]Either[java.lang.String,X]。这似乎是由于(或至少与)scalac 拒绝推断部分应用的类型构造函数有关。

(与此相关的是,这是 Scala 认为复杂得令人无法接受的类型之一的示例)。