对于依赖的方法类型,有哪些令人信服的用例?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (23)

Heiko Seeberger发布了一个依赖方法类型的简单示例。如注释中所示,可以很容易地使用方法上的类型参数进行再现。

对于依赖的方法类型,有哪些实用的、有用的例子,它们显然比其他方法更有利?我们能用它们做些以前不可能/不容易的有趣的事情吗?他们为我们买了什么现有的类型系统功能?

提问于
用户回答回答于

成员(即嵌套)类型的任何使用或多或少都会引起对依赖方法类型的需求

那有什么问题吗?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/ResourceFileManager/File它们反过来又被NetworkFileManager/RemoteFile)。这是一个很好的例子,但它的模式是真实的:它在Scala编译器中使用,并且在ScalaEclipse插件中被广泛使用。

下面是使用中的抽象的一个例子,

val nfm = new NetworkFileManager
val rf : nfm.Resource = nfm.create
nfm.testHash(rf)
nfm.testDuplicates(rf)

注意,路径依赖意味着编译器将确保testHashtestDuplicates方法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)
用户回答回答于
trait Graph {
  type Node
  type Edge
  def end1(e: Edge): Node
  def end2(e: Edge): Node
  def nodes: Set[Node]
  def edges: Set[Edge]
}

在其他地方,我们可以静态地保证我们没有将两个不同的图中的节点混合在一起,例如:

def shortestPath(g: Graph)(n1: g.Node, n2: g.Node) = ... 

当然,如果在内部定义,这个方法已经起作用了。Graph,但是说我们不能修改Graph正在为它写一个分机。

扫码关注云+社区