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

时间:2014-04-04 12:09:28

标签: scala

给出

trait Foo {
  type Bar
}

是否有合法的方法来编写类似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)
}

2 个答案:

答案 0 :(得分: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>

您可能还注意到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.

另请参阅thisthis个问题。


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

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)
}

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

答案 1 :(得分:1)

Scala 3预计将于今年(2020年)发布。它将具有(实际上已经具有)依赖的函数类型,在“ Dotty”文档中对此进行了描述:

https://dotty.epfl.ch/docs/reference/new-types/dependent-function-types.html