Scala:将函数定义为正确的类型

时间:2011-11-15 14:03:45

标签: scala

我一直在使用Scala代码,遇到了我不理解的编译器错误。代码生成一对Ints的向量,然后尝试过滤它。

val L = for (x <- (1 to 5)) yield (x, x * x) 
val f = (x: Int, y: Int) => x > 3
println(L.filter(f))

编译器抱怨尝试使用f作为filter方法的参数,编译器错误消息为:

error: type mismatch;
found   : (Int, Int) => Boolean
required: ((Int, Int)) => Boolean

如何正确定义函数f以满足所需的函数类型?我尝试在(x: Int, y: Int)附近添加额外的括号,但这给了:

error: not a legal formal parameter
   val f = ((x: Int, y: Int)) => x > 3
            ^

3 个答案:

答案 0 :(得分:13)

f的类型为Function2[Int, Int, Boolean]L的类型为IndexedSeq[Tuple2[Int, Int]],因此filter需要Function1[Tuple2[Int, Int], Boolean]类型的函数。每个FunctionN[A, B, .., R]特征都有一个方法tupled,它返回类型为Function1[TupleN[A, B, ..], R]的函数。您可以在此处使用它将f转换为L.filter预期的类型。

println(L.filter(f.tupled))
> Vector((4,16), (5,25))

或者,您可以按照以下方式将f重新定义为Function1[Tuple2[Int, Int], Boolean]并直接使用。

val f = (t: (Int, Int)) => t._1 > 3
println(L.filter(f))
> Vector((4,16), (5,25))

答案 1 :(得分:6)

val f = (xy: (Int, Int)) => xy._1 > 3
println (L.filter (f))

如果你这样做

val f = (x: Int, y: Int) => x > 3

你定义了一个带有两个整数的函数,这个函数与一对整数作为参数的函数不同。

比较

scala> val f = (x: Int, y: Int) => x > 3
f: (Int, Int) => Boolean = <function2>

scala> val f = (xy: (Int, Int)) => xy._1 > 3
f: ((Int, Int)) => Boolean = <function1>

答案 2 :(得分:0)

如果您不想重写函数以明确使用Tuple2(由missingfaktor和用户未知建议),您可以定义一个隐式方法来自动执行。这使得函数f不受影响(你不必总是用Tuple2参数调用它)并且更容易理解,因为你仍然使用标识符x和y。

implicit def fun2ToTuple[A,B,Res](f:(A,B)=>Res):((A,B))=>Res = 
  (t:(A,B)) => f(t._1, t._2)
val L = for (x <- (1 to 5)) yield (x, x * x)
val f = (x: Int, y: Int) => x > 3
val g = (x: Int, y: Int) => x % 2 > y % 3
L.filter(f)    //> Vector((4,16), (5,25))
L.filter(g)    //> Vector((3,9))
f(0,1)         //> false
f((4,2))       //> true

现在每个Function2也可以用作带有Tuple2作为参数的Function1,因为它在需要时使用隐式方法转换函数。

对于具有两个以上参数的函数,隐式defs看起来类似:

implicit def fun3ToTuple[A,B,C,Res](f:(A,B,C)=>Res):((A,B,C))=>Res = 
  (t:(A,B,C)) => f(t._1, t._2, t._3)
implicit def fun4ToTuple[A,B,C,D,Res](f:(A,B,C,D)=>Res):((A,B,C,D))=>Res = 
  (t:(A,B,C,D)) => f(t._1, t._2, t._3, t._4)
...