如何正确定义类型lambda?



我使用=:=作为示例类型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#lT => 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#lCurry#lCurrStatic#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]]

最新更新