[英]Understanding Dependent Types
鉴于:
scala> sealed trait Parent
defined trait Parent
scala> case object Boy extends Parent
defined object Boy
scala> case object Girl extends Parent
defined object Girl
scala> trait F {
| type A
| def x: A
| }
defined trait F
scala> case object FImpl extends F {
| override type A = Parent
| def x: Parent = Boy
| }
defined object FImpl
然后,我定义了一个方法:
scala> def foobar(f: F)(matcher: f.A => Boolean): Boolean =
| matcher(f.x)
foobar: (f: F)(matcher: f.A => Boolean)Boolean
scala> foobar(FImpl)(_ match { case Boy => true; case Girl => false})
res3: Boolean = true
我对这是如何工作感到困惑。 编译器必须在编译时知道fA
的类型吗?
您的问题基本上是:当f
是运行时值时,编译器如何看到成员fA
? 答案是事实并非如此。 从语法上讲, fA
看起来像是在访问f
的成员,但实际上,它仅依赖于f
的类型。
当你写:
object FImpl extends F {
override type A = Parent
def x: Parent = Boy
}
FImpl
定义了一个新的单例类型,称为FImpl.type
。 因此, FImpl.type#A
是Parent
。
调用foobar
, f.type
被标识为FImpl.type
,因此fA
aka f.type#A
就是FImpl.type#A
aka Parent
。
考虑以下两个示例:
def needsParent(p: Parent) = ???
def foobar(f: F)(matcher: f.A => Boolean) = ???
foobar(FImpl)(needsParent) // Works
foobar(FImpl: F)(needsParent) // Does not work
尽管运行时值相同,但类型不同,因此编译器接受一个并拒绝另一个。
换句话说,Scala的从属类型是一个巧妙的虚构-实际上,类型从不依赖于实际的运行时值。 但是事实证明,仅通过将类型与其他类型标识在一起,就可以在有限的范围内跟踪值,从而给依赖于值的类型留下印象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.