2013-03-07 88 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

相关问题