我使用=:=
作为示例类型lambda,目的是制作简单的最小示例。
=:=
类型需要两个参数,我想在类型级别上讨论一个参数。
我采用幼稚的实现type Curry[G] = {type l[L] = L =:= G}
但在实际使用中会导致错误:
type X = Int
type Y = Int
type CurryInt[T] = T =:= Int
type Curry[G] = {type l[L] = L =:= G}
type CurrStatic = {type l[L] = L =:= Int}
object CurryObj {type l[L] = L =:= Int}
trait Apply[P[_], T]
implicit def liftApply[P[_], T](implicit ev : P[T]) = new Apply[P,T] {}
implicitly[Apply[CurryInt, Y]] // ok
implicitly[Apply[Curry[X]#l, Y]] // fails
implicitly[Apply[Curry[X]#l, Y]](liftApply) // fails
implicitly[Apply[Curry[X]#l, Y]](liftApply[Curry[X]#l, Y]) // ok
implicitly[Apply[CurrStatic#l, Y]] // fails
implicitly[Apply[CurryObj.l, Y]] // ok
类型推断在此处中断。我应该如何定义类型 lambda 以使其工作?
请考虑以下示例的简化版本:
trait Secret
type Curry = { type l[L] = Secret }
def foo[P[_], T](ev : P[T]) = ???
val bar: Curry#l[Int] = ???
foo(bar)
当调用foo
值时,bar
只是类型Secret
,编译器不知道你的特定Secret
来自哪里。
您的bar
值只是一个Secret
,它不会维护指向Curry#l[Int]
的信息。
编译器无法推断该P => Curry#l
并T => Int
。
编译器只能看到Secret
并丢失Curry#l
上下文,尽管使用Curry#l[Int]
而不是Secret
注释类型。
另一个例子(来自这个问题(,暴露了类似的行为:
trait Curry { type l }
trait CurryB extends Curry { type l = String }
def foo[P <: Curry](x: P#l) = ???
val bar: CurryB#l = ???
foo(bar)
CurryObj
情况不同,请考虑CurryInt#l
、Curry#l
和CurrStatic#l
只是类型别名。 相反,CurryObj.l
是一个实际类型,是具体对象CurryObj
的一部分。
让我们来看看这个(REPL(:
scala> trait Secret
defined trait Secret
scala> type Curry = { type l[L] = Secret }
defined type alias Curry
scala> object CurryObj { type l[L] = Secret }
defined object CurryObj
scala> object S extends Secret
defined object S
scala> val foo0: Curry#l[Int] = S
foo0: Secret = S$@2c010477
scala> val foo1: CurryObj.l[Int] = S
foo1: CurryObj.l[Int] = S$@2c010477
请注意,类型别名Curry#l[Int]
->Secret
会立即解析,而是保留实际的类型CurryObj.l[Int]
。
稍微冗长一些,但编译:)(斯卡拉 2.12.3(
type X = Int
type Y = Int
type CurryInt[T] = T =:= Int
type Curry[G] = {type l[L] = =:=[L, G]}
type CurrStatic = {type l[L] = L =:= Int}
object CurryObj {type l[L] = L =:= Int}
trait Apply[P[_], T]
implicit def liftApply[P[_], T](implicit ev : P[T]) = new Apply[P,T] {}
type L1[R] = =:=[R, X]
type L2[R] = =:=[R, Int]
implicitly[Apply[CurryInt, Y]] // ok
implicitly[Apply[L1, Y]] // ok
implicitly[Apply[L1, Y]](liftApply[L1, Y]) // ok
implicitly[Apply[Curry[X]#l, Y]](liftApply[Curry[X]#l, Y]) // ok
implicitly[Apply[L2, Y]] // ok
implicitly[Apply[CurryObj.l, Y]] // ok
似乎 scala 编译器无法处理类型投影中的裸类型。我跟踪了-Ytyper-debug
输出,发现所有需要的类型信息都被带走了,但没有明显的原因被拒绝。但是仍然可以在特征中获取类型lambdas包装表达式。这个答案让我对解决方案有了深刻的了解。
type X = Int
type Y = Int
trait Wrap {
type l[T]
}
trait GenWrap[W[_]] extends Wrap {
final type l[T] = W[T]
}
type CInt[T] = T =:= Int
class CurryInt extends Wrap {type l[T] = T =:= Int}
class Curry[U] extends Wrap {type l[T] = T =:= U}
type TCurry[U] = Wrap {type l[T] = T =:= U}
trait Apply[W <: Wrap, T]
implicit def lift[W <: Wrap, T](implicit ev : W#l[T]) = new Apply[W,T] {}
implicitly[Apply[CurryInt, Y]]
implicitly[Apply[Curry[X], Y]]
implicitly[Apply[TCurry[X], Y]]
implicitly[Apply[GenWrap[CInt], Y]]