2013-03-07 87 views
15

是否有一個語法來允許函數文字的泛型類型參數?我知道我可以在一個方法把它包起來,如:在Scala中,泛型類型參數可以與* function *定義一起使用嗎?

def createLongStringFunction[T](): (T) => Boolean = { 
    (obj: T) => obj.toString.length > 7 
} 

但後來我最終需要調用每一個類型T的方法,並得到一個新的功能。我翻看了語言參考,雖然我看到函數文字語法被編譯器翻譯爲一個實例,它本身具有通用輸入類型,但它看起來像編譯器magic在實現時會實現這些參數創建。我還沒有找到任何語法允許我實際上「讓一個或多個類型參數保持不受限制」。我更喜歡的是:

// doesn't compile 
val longStringFunction: [T](T) => Boolean = (obj: T) => obj.toString.length > 7 

有沒有這樣的事情存在?或者就此而言,當擴展的方法具有泛型參數時,eta-expansion函數的顯式類型是什麼?

這是一個純粹做作和無用的例子。當然,我可以在這裏使用「任何」功能。

回答

18

不,類型參數只適用於方法而不適用於函數對象。例如,

def f[T](x: T) = x  //> f: [T](x: T)T 
val g = f _   //> g: Nothing => Nothing = <function1> 
// g(2)    // error 
val h: Int=>Int = f _ //> h : Int => Int = <function2> 
h(2)     //> res0: Int = 2 

方法f不能被轉換到一個多態函數對象g。如您所見,g的推斷類型實際上是Function1[Nothing, Nothing],這是無用的。然而,對於類型提示,我們可以構造h: Function1[Int,Int],其按照預期的方式工作,參數爲Int

+0

謝謝,我很害怕,可能是這樣。不過,以這種方式擴展該方法確實爲更復雜的案例打開了大門。雖然我找不到中間方法來做到這一點,但賦值時的類型提示可以帶來如此驚人的效果,例如:012ff'def doStuff [T,U](moreStuff:T => U)(obj: T)= moreStuff(obj) val timeAndAHalf = doStuff [Int,Double](_ * 1.5)_' 其中有相當一部分從其明確的對應部分中刪除 'def doStuff [T,U](moreStuff:T => U = moreStuff(obj) val timeAndAHalf:Int => Double =(num:Int)=> doStuff [Int,Double](num => num * 1.5)(num)' – erich2k8 2013-03-08 04:09:13

+4

是類型參數不適用於函數對象的原因? – 2014-02-21 12:34:58

1

由於定義爲遵循longStringFunction,其必須具有一定的給定類型

val longStringFunction: (T) => Boolean = (obj: T) => obj.toString.length > 7 

但是,您可以重複使用的功能對象與方法:

scala> val funObj: Any => Boolean = _.toString.size > 7 
funObj: Any => Boolean = <function1> 

scala> def typedFunction[T]: T => Boolean = funObj 
typedFunction: [T]=> T => Boolean 

scala> val f1 = typedFunction[String] 
f1: String => Boolean = <function1> 

scala> val f2 = typedFunction[Int] 
f2: Int => Boolean = <function1> 

scala> f1 eq f2 
res0: Boolean = true 

這工作,因爲trait Function1[-T1, +R]T1逆變

+0

真的。這實際上只是將其轉換爲更受限制的類型。實際上,我們可以完全放棄該方法並簡單地分配該功能,例如 'val f1:String => Boolean = funObj' – erich2k8 2013-03-08 03:06:32

7

正如你所說,在你的例子中,你所要求的是toString方法,所以Any將是通常的解決方案。然而,在要求在元組中的每個元素上應用類型構造函數(例如List)的情況下,可以使用更高級的類型。

至於其他的答案中提到,有一個爲這個沒有直接的支持,但有一個相對不錯的方式對其進行編碼:

trait ~>[A[_],B[_]] { 
    def apply[X](a : A[X]) : B[X] 
} 

type Id[A] = A //necessary hack 

object newList extends (Id ~> List) { 
    def apply[X](a : Id[X]) = List(a) 
} 

def tupleize[A,B, F[_]](f : Id ~> F, a : A, b : B) = (f(a), f(b)) 

tupleize(newList, 1, "Hello") // (List(1), List(Hello)) 
1

在Scala中,函數值參單態(而方法是多態)

無形體庫引入了多態函數值,可以映射到HList和更多其他功能。

請考慮下面的裁判: http://www.chuusai.com/2012/04/27/shapeless-polymorphic-function-values-1/ http://www.chuusai.com/2012/05/10/shapeless-polymorphic-function-values-2/

+0

雖然這個鏈接可能回答這個問題,但最好在這裏包含答案的重要部分,並提供供參考的鏈接。如果鏈接頁面更改,則僅鏈接答案可能會失效。 – Sasa 2014-12-26 10:32:46

+0

@Sasam答案確實包括答案的重要部分! – 2014-12-26 11:28:05

相關問題