根据我的理解,以下两个函数及其调用应该是相同的:
def f1[L1 <: HList, L2](xs: L1)(implicit sequencer: Sequencer.Aux[L1, Option, L2]) {
println(xs.sequence)
}
def f2[L1 <: HList : Sequencer.Aux[*, Option, L2], L2](xs: L1) {
println(xs.sequence)
}
f1[Option[Int] :: Option[String] :: HNil, Int :: String :: HNil](Some(42) :: Some("foo") :: HNil)
f2[Option[Int] :: Option[String] :: HNil, Int :: String :: HNil](Some(42) :: Some("foo") :: HNil)
然而,对f2的调用没有编译:
could not find implicit value for evidence parameter of type cats.sequence.Sequencer[Option[Int] :: Option[String] :: shapeless.HNil]{type F[X] = Option[X]; type LOut = Int :: String :: shapeless.HNil}
Scala编译似乎在第二种情况下扩展了类型别名Sequencer.Aux,并且无法构造合适的隐式。
如果我直接用扩展类型定义我的函数,那么也不能构造隐式:
def f3[L1 <: HList, L2](xs: L1)(implicit sequencer: Sequencer[L1]{type F[X] = Option[X]; type LOut = L2}) {
println(xs.sequence)
}
除了不能使用更紧凑的上下文绑定语法带来的不便之外,还有两件事我不理解这种情况:
- 为什么只有当我使用上下文绑定语法时,隐式证据的类型才会扩展?(这两种语法在语义上有更多的区别吗?(
- 为什么Scala不能为扩展的情况构建一个合适的隐式?毕竟,Sequencer.Aux只是一个定义如下的类型别名:
type Aux[L <: HList, F0[_], LOut0] = Sequencer[L] {
type F[X] = F0[X]
type LOut = LOut0
}
我本以为这两种类型的行为完全相同。
看起来像一个bug。应在此处报告Bug:https://github.com/scala/bug/issues
我试图创造一个最小的例子。
也许我过于简化了这个例子,但现在我甚至在
HNil
的情况下也有问题。
对于
import cats.Applicative
import shapeless.{::, HList, HNil}
import cats.instances.option._
trait Sequencer[L <: HList] extends Serializable {
type F[_]
}
object Sequencer {
type Aux[L <: HList, F0[_]] = Sequencer[L] {
type F[X] = F0[X]
}
implicit def nil[F0[_]](
implicit F: Applicative[F0]
): Aux[HNil, F0] = null
}
implicitly[Sequencer.Aux[HNil, Option]]
编译,但implicitly[Sequencer[HNil]{type F[X] = Option[X]}]
不编译,并且存在警告(scalacOptions += "-Xlog-implicits"
(
//Information: App.this.Sequencer.nil is not a valid implicit value for App.Sequencer[shapeless.HNil]{type F[X] = Option[X]} because:
//hasMatchingSymbol reported error: could not find implicit value for parameter F: cats.Applicative[Option[X]]
也许在这里我们可以看到原因:could not find implicit value for parameter F: cats.Applicative[Option[X]]
应该是could not find implicit value for parameter F: cats.Applicative[Option]
。
但出于某种原因,如果我删除implicit F: Applicative[F0]
,那么对于
import shapeless.{::, HList, HNil}
trait Sequencer[L <: HList] extends Serializable {
type F[_]
}
object Sequencer {
type Aux[L <: HList, F0[_]] = Sequencer[L] {
type F[X] = F0[X]
}
implicit def nil[F0[_]](): Aux[HNil, F0] = null
}
虽然implicitly[Sequencer.Aux[HNil, Option]](Sequencer.nil())
进行了编译,但implicitly[Sequencer.Aux[HNil, Option]]
不进行编译。
implicitly[Sequencer[HNil]{type F[X] = Option[X]}]
也不编译。如果我们写implicitly[Sequencer[HNil]{type F[X] = Option[X]}](Sequencer.nil())
,我们就会明白为什么
//Error: inferred kinds of the type arguments (Option[X]) do not conform to the expected kinds of the type parameters (type F0).
//Option[X]'s type parameters do not match type F0's expected parameters:
//class Option has one type parameter, but type F0 has one
... has one type parameter, but ... has one
显示这是一个错误
Bug跟踪器显示"隐式"one_answers"高级"的开放问题
https://github.com/scala/bug/issues?utf8=%E2%9C%93&q=是%3Issue+是%3Open+隐式+高级