我想定义一些特性,这些特性具有良好定义的关系 - 例如,我们假设a * b = c
。这个想法是,这个特质的实现可以提供其中的两个,并为第三个属性自动生成一个访问器。在Scala中推断相互依赖的默认方法实现
(这是两个不同的功能Haskell的类型类,如果我没有记错的正确,在那里,如果你从(我没记错的Haskell的类型类)Ord
定义<
,>=
将被实现为! . <
- 尽管你可以这么久定义功能任何子集作为剩余部分, 。可以推断)
天真的方法确实可以工作得相当好。
trait Foo {
// a * b = c
def a: Double = c/b
def b: Double = c/a
def c: Double = a * b
}
class FooOne(override val a: Double, override val b: Double) extends Foo
class FooTwo(override val a: Double, override val c: Double) extends Foo
这里,实现FooOne
和FooTwo
是Foo
的完整实现,并且按预期运行。到现在为止还挺好;这种方法确实允许类定义两个属性并获得第三个“免费”。
然而,事情开始变得不那么乐观,如果一个限定了第三类:
class FooFail(override val a: Double) extends Foo
这将编译就好了 - 但是,它会导致堆栈溢出如果b
或c
方法是不断进行评估。
那么幼稚的方法给出了Haskell的类型类方法的推断方面,但我们没有编译时的安全性。如果少于两个的方法是通过实现类来定义的,我希望编译器能够投诉。显然目前的语法在这里是不够的;我们需要将这些方法视为抽象的,尽管只有当依赖方法非抽象时才可以使用默认实现。
Scala是否公开适当的语义来定义这个? (如果定义它有点迂回的方式,我没有问题,类似于union types,因为我不知道该语言对此有任何一流的支持)。
如果不是的话,我会用幼稚的方法来做,并且仔细地定义和测试我的课程。但我真的认为这是类型系统应该能够捕获的东西(毕竟 - 它不是Ruby。:))。
除非我完全记错,否则Haskell对于同样的问题使用完全相同的天真方法。 –
@Alexey - 有趣的评论。这已经有一段时间了,但我似乎记得,如果你没有定义足够多的方法,你会得到一个编译器/解释器错误,导致无法为类型类派生所有方法。也许我会试着重现这一点,并阅读Haskell如何做,以获取灵感。 –
好吧,在Haskell中测试过它确实遭受同样的问题(它相当于Scala的情况,它只会警告完全抽象的方法)。尽管如此,这个问题仍然存在,尽管没有另一种语言的先例。 –