是否可以在Scala中写下依赖函数类型?

Ale*_*nov 16 scala

特定

trait Foo {
  type Bar
}
Run Code Online (Sandbox Code Playgroud)

是否有合法的方法来编写类似的东西f: (x: Foo) => x.Bar,以便函数的返回类型取决于参数?使用的一个例子是

def compareOutput(x1: Foo, x2: Foo)(f: (x: Foo) => x.Bar /* illegal */)(comparer: (x1.Bar, x2.Bar) => Boolean) = {
  val y1 = f(x1)
  val y2 = f(x2)
  comparer(y1, y2)
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ing 8

Scala不具有多态函数,例如Haskell.函数类型总是具体的.只有方法可以是多态的.不幸的是,这意味着您的假设类型(x: Foo) => x.Bar在Scala中无法表达.

将泛型方法转换为函数时,这一点很明显:所有类型信息都丢失了:

scala> def foo[Bar](x: Bar): Bar = ???
foo: [Bar](x: Bar)Bar

scala> foo _
res1: Nothing => Nothing = <function1>
Run Code Online (Sandbox Code Playgroud)

您可能还注意到scala无法将具有依赖类型的方法转换为函数.那是因为不可能满足你的假设类型:

scala> def foo(x: Foo): x.Bar = ???
foo: (x: Foo)x.Bar

scala> foo _
<console>:10 error: method with dependent type (x: Foo)x.Bar cannot be converted 
                    to function value.
Run Code Online (Sandbox Code Playgroud)

另见这个这个问题.


但是,您的问题有几种解决方案.一种方法是将依赖类型的方法封装在辅助特征中:

trait FooFunc {
  def apply(x: Foo): x.Bar
}

def compareOutput(x1: Foo, x2: Foo)(f: FooFunc)(comparer: ...) = {
  val y1 = f(x1)
  val y2 = f(x2)
  comparer(y1,y2)
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建FooFunc的实例,您可以将其传递给您的compareOutput方法.