路径依赖类型示例不起作用

时间:2016-06-10 20:07:05

标签: scala path-dependent-type

Scala n00b在这里。很确定我理解PDT,但是确定并遇到了问题;这里是上一个问题Scala types: Class A is not equal to the T where T is: type T = A,其中包含示例代码,我将在此处重现:

1: class Food
2: class Fish extends Food
3: class Grass extends Food
4:
5: abstract class Animal {
  6: type SuitableFood <: Food
  7: def eat(food: SuitableFood)
8: }
9: 
10: class Cow extends Animal {
  11: type SuitableFood = Grass
  12: override def eat(food: Grass) {}
13: }
14: 
15: val bessy: Animal = new Cow  // [1]
16: 
17: bessy eat (new bessy.SuitableFood) // [2]

原始海报说这个编译,我认为应该,但它不会。如果我将它粘贴到scala REPL中,它会成功创建bessy [1]:

scala> val bessy: Animal = new Cow
bessy: Animal = Cow@165b8a71

但是[2],给了我一个我不理解的错误:

scala> bessy.eat(bessy.SuitableFood)
<console>:17: error: value SuitableFood is not a member of Animal
       bessy.eat(bessy.SuitableFood)
                       ^

如果我将其粘贴到文件中并且“scalac&#39;它,我也一样。为什么? bessy是一个牛对象,其中定义了type SuitableFood = Grassbessy.SuitableFood是一个类类型(不是吗?)。 怎么了?

1 个答案:

答案 0 :(得分:2)

  1. new中缺少(new bessy.SuitableFood)

  2. 解决此问题后,bessy被定义为类型Animal,而不是Cow,因此编译器不会知道{{ 1}}是bessy.SuitableFood:它只是一个抽象类型,因此Grass不起作用(如new bessy.SuitableFood不是new A时类型参数)。例如。考虑A的某些其他子类型可以声明Animal,而type SuitableFood = Food是非法的。 我已经检查了,它确实在2.10.6中编译,但我相信这是一个修复过的错误。

  3.   因此,我认为“新的bessy.SuitableFood”将返回一个合适的食物,因为.SuitableFood将是一种虚拟类型,所以当'Cow'然后'SuitableFood'将是'草'。如果他们不这样做,我不会看到PDT的价值。

    这里PDT的重点是,如果你有一个new Foodbessy.SuitableFood可以吃掉它;并且她不能吃bessy(除非编译器静态知道它是一个子类型)。但是这个例子没有给出产生spot.SuitableFood的任何方法,因为没有理由假设(并且无法告诉编译器)bessy.SuitableFood是一个带有公共无参数构造函数的类。您可以通过向type SuitableFood添加方法来修复它:

    Animal

    现在abstract class Animal { type SuitableFood <: Food def eat(food: SuitableFood) def newSuitableFood(): SuitableFood } class Cow extends Animal { ... def newSuitableFood() = new Grass } 将编译并运行。