2014-04-04 53 views
16

鑑於是否可以在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) 
} 
+0

請參閱示例[Miles Sabin如何在無形中使用依賴方法類型](https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/syntax/hlists.scala) 。 –

+2

我不認爲這是相關的。他希望能夠定義一個函數類型(而不僅僅是定義一個方法),其中返回類型取決於參數值。我相信這目前是不可能的。即使你設法定義一個匹配OP意圖的類型,我不認爲你能夠將一個方法作爲參數'f'來傳遞,因爲eta-expansion不支持依賴方法類型。請參閱https://issues.scala-lang.org/browse/SI-4751。這會迫使我們以一種相當尷尬的方式來定義這些「依賴函數」,比如擴展一個自定義特徵並實現其「應用」方法。 –

+0

@RégisJean-Gilles:你說得對 - 我可能讀得太快了。你所描述的可以通過Shapeless的多態函數值來完成,但不是vanilla Scala函數。 –

回答

8

斯卡拉沒有多態功能,例如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) 
} 

然後,您可以創建可傳遞到您的compareOutput方法FooFunc的實例。

相關問題