【问题标题】:Scala: Defining a function to be the correct typeScala:将函数定义为正确的类型
【发布时间】:2013-05-06 00:06:50
【问题描述】:

我一直在使用 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
            ^

【问题讨论】:

  • 这个问题是消除参数列表和元组之间区别的参数。也就是说,现在,f(x,y) 中的 (x,y) 与纯 (x,y) 本身是不同的东西。不幸的是,消除这种区别在技术上并不简单。

标签: scala


【解决方案1】:

f 的类型为 Function2[Int, Int, Boolean]L 的类型是 IndexedSeq[Tuple2[Int, Int]],因此 filter 需要 Function1[Tuple2[Int, Int], Boolean] 类型的函数。每个FunctionN[A, B, .., R] trait 都有一个方法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))

【讨论】:

    【解决方案2】:
    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>
    

    【讨论】:

      【解决方案3】:

      如果您不想将函数重写为显式使用 Tuple2(如 missingfaktor 和 user unknown 建议的那样),您可以定义一个隐式方法来自动执行此操作。这使得函数 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 也可以作为 Function1 使用 Tuple2 作为参数,因为它使用隐式方法在需要时转换函数。

      对于具有两个以上参数的函数,隐式定义看起来很相似:

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

      【讨论】:

        猜你喜欢
        • 2017-05-02
        • 1970-01-01
        • 1970-01-01
        • 2016-06-24
        • 2011-11-05
        • 1970-01-01
        • 2016-08-03
        • 2019-06-01
        • 1970-01-01
        相关资源
        最近更新 更多