成员(即嵌套)类型的任何使用或多或少都会引起对依赖方法类型的需求。特别是,我坚持认为,如果没有依赖的方法类型,那么经典的蛋糕模式更接近于成为反模式。
所以有什么问题?Scala中的嵌套类型取决于其封闭实例。因此,在没有依赖方法类型的情况下,尝试在该实例之外使用它们可能会非常困难。这可以将最初看起来很优雅且吸引人的设计转变成噩梦般僵硬且难以重构的怪兽。
我将通过在我的高级Scala培训课程中进行的练习来说明这一点,
trait ResourceManager {
type Resource <: BasicResource
trait BasicResource {
def hash : String
def duplicates(r : Resource) : Boolean
}
def create : Resource
// Test methods: exercise is to move them outside ResourceManager
def testHash(r : Resource) = assert(r.hash == "9e47088d")
def testDuplicates(r : Resource) = assert(r.duplicates(r))
}
trait FileManager extends ResourceManager {
type Resource <: File
trait File extends BasicResource {
def local : Boolean
}
override def create : Resource
}
class NetworkFileManager extends FileManager {
type Resource = RemoteFile
class RemoteFile extends File {
def local = false
def hash = "9e47088d"
def duplicates(r : Resource) = (local == r.local) && (hash == r.hash)
}
override def create : Resource = new RemoteFile
}
这是典型的蛋糕模式的一个例子:我们有一个家庭的抽象,它们通过层次结构逐步细化的(ResourceManager
/ Resource
是由精制FileManager
/ File
这是又被细化NetworkFileManager
/ RemoteFile
)。这是一个玩具示例,但是模式是真实的:它在整个Scala编译器中使用,并在Scala Eclipse插件中广泛使用。
这是一个使用中的抽象的例子,
val nfm = new NetworkFileManager
val rf : nfm.Resource = nfm.create
nfm.testHash(rf)
nfm.testDuplicates(rf)
请注意,路径依赖性意味着编译器将保证只能使用与之对应的参数调用on testHash
和testDuplicates
方法NetworkFileManager
,即。它是自己的RemoteFiles
,仅此而已。
无疑,这是一个理想的属性,但是假设我们想将此测试代码移至其他源文件?使用相关方法类型,可以很容易地在ResourceManager
层次结构之外重新定义这些方法,
def testHash4(rm : ResourceManager)(r : rm.Resource) =
assert(r.hash == "9e47088d")
def testDuplicates4(rm : ResourceManager)(r : rm.Resource) =
assert(r.duplicates(r))
请注意此处使用的依赖方法类型:第二个参数(rm.Resource
)的类型取决于第一个参数(rm
)的值。
可以在没有依赖的方法类型的情况下执行此操作,但是这非常尴尬,并且机制非常不直观:我已经教了这门课程近两年了,那时,没有人提出一个可行的解决方案。
自己尝试一下...
// Reimplement the testHash and testDuplicates methods outside
// the ResourceManager hierarchy without using dependent method types
def testHash // TODO ...
def testDuplicates // TODO ...
testHash(rf)
testDuplicates(rf)
在苦苦挣扎了片刻之后,您可能会发现为什么我(或者也许是戴维·麦克维,我们不记得我们中谁创造了这个术语)为什么称其为“末日面包店”。
编辑:共识是末日面包房是大卫·麦克弗(David MacIver)的造币...
值得一提的是:Scala依赖类型的形式(以及依赖方法类型的一部分)通常受到编程语言Beta的启发……它们自然源于Beta一致的嵌套语义。我什至不知道还有其他任何形式的依赖类型的主流编程语言。诸如Coq,Cayenne,Epigram和Agda之类的语言具有不同形式的依存类型,在某些方面更通用,但由于属于类型系统而与Scala不同,后者没有子类型,因此存在显着差异。