【问题标题】:How to define and invoke a partially applied function with varargs?如何使用可变参数定义和调用部分应用的函数?
【发布时间】:2012-11-10 14:32:57
【问题描述】:

堆栈溢出:

大家好。

我想定义一个具有可变参数的部分应用函数。

为了确认,我准备了几个函数,即 Functions._。 除了 func 之外的函数都有一个可变参数。

如何使用可变参数定义和调用部分应用的函数? (例如,带有可变参数的 gunc1。)

java版本“1.7.0_07” Scala 代码运行器版本 2.9.1.final

object Functions {
    def func(x: Int, y: Int) = x + y
    def gunc(x: Int*) = x.sum
    def hunc(x: Int, y: Int*) = x + y.sum
    def iunc(x: Int)(y: Int*) = x + y.sum // curried
    def junk(x: String, y: Int*) = x + y.sum
}

object PartiallyApplied extends App {
    import Functions._

    val func0 = func(1, _: Int) // I can.
    println("result: " + func0(2))

    val gunc0 = gunc(1, _: Int) // I can invoke if I specify the varargs.size. But gunc0 no longer has varargs...
    println("result: " + gunc0(2))

//    val gunc1 = gunc(1, _: Int*) => compile error: ')' expected but identifier found.
//    val gunc1 = gunc(1, _: Seq[Int]) => compile error: type mismatch | found: Seq[Int] | required: Int
    val gunc1 = gunc(1, _: Int) // I can invoke if I specify the varargs.size. But gunc1 no longer has varargs...
    println("result: " + gunc1(2))

//    val hunc0 = hunc(1)_ => compile error: _ must follow method; cannot follow Int
//    val hunc0 = hunc(1, _: Int*) => compile error: ')' expected but identifier found.
//    val hunc0 = hunc(1, _: Seq[Int]) => compile error: type mismatch | found: Seq[Int] | required: Int
    val hunc0 = hunc(1, _: Int) // I can invoke if I specify the varargs.size. But hunc0 no longer has varargs...
    println("result: " + hunc0(2))
//    println("result: " + hunc0(2, 3)) => compile error: too many arguments for method apply: (v1: Int)Int in trait Function1
//    println("result: " + hunc0((2, 3): _*)) => compile error: type mismatch | found: (Int, Int) | required: Seq[Int]
//    println("result: " + hunc0(Seq(2, 3))) => compile error: type mismatch | found: Seq[Int] | required: Int
//    println("result: " + hunc0(Seq(2, 3): _*)) => compile error: no `: _*' annotation allowed here (such annotations are only allowed in arguments to *-parameters)

    val hunc1 = hunc(1, _: Int, _: Int) // I can invoke if I specify the varargs.size. But hunc1 no longer has varargs...
    println("result: " + hunc1(2, 3))

    val hunc2 = hunc(1, _: Int, _: Int, _:Int) // I can invoke if I specify the varargs.size. But hunc2 no longer has varargs...
    val hunc3 = hunc2(2, _: Int, _: Int)
    val hunc4 = hunc3(3, _: Int)
    println("result: " + hunc4(4))

    println("result: " + hunc5(2, 3))

//    val iunc0 = iunc(1)(_: Int*) => compile error: ')' expected but identifier found.
//    val iunc0 = iunc(1)(_: Seq[Int]) => compile error: type mismatch | found: Seq[Int] | required: Int
    val iunc0 = iunc(1)(_: Int)
    println("result: " + iunc0(2))

    val iunc1 = iunc(1)(_: Int, _: Int)
    println("result: " + iunc1(2, 3))
}

object NotPartiallyApplied extends App {
    import Functions._

    println("result: " + gunc(1))
    println("result: " + gunc(1, 2, 3))
    println("result: " + gunc(Seq(1, 2, 3): _*))

    println("result: " + hunc(1))
    println("result: " + hunc(1, 2, 3))
    println("result: " + hunc(1, Seq(2, 3): _*))

    println("result: " + iunc(1)(2, 3))
    println("result: " + iunc(1)(Seq(2, 3): _*))

    println("result: " + junk("x"))
    println("result: " + junk("x", 2, 3))
    println("result: " + junk("x", Seq(2, 3): _*))
}

[在 Rex Kerr 的评论后编辑]

我想要像下面的 guncN 这样的部分应用函数:

val guncN = gunc(1, _: Int*)
println("result: " + guncN(2)) // => 3
println("result: " + guncN(2, 3)) // => 6
println("result: " + guncN(2, 3, 4, 5, 100)) // => 115

但被scalac禁止。

我认为 guncN 每次都应该评估,在时间 (2)、(2, 3) 和 (2, 3, 4, 5, 100) 给出。 下面我们不需要guncM:

val guncM = guncN(2, _: Int*)
println("result: " + guncM(3, 4)) // => 10

【问题讨论】:

    标签: scala


    【解决方案1】:

    如果你只想要可变参数,你可以在 2.9 中:

    Welcome to Scala version 2.9.1.final
    (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_31).
    ...
    scala>     def sum(xs: Int*) = xs.sum
    sum: (xs: Int*)Int
    
    scala>     val summer = sum _
    summer: Int* => Int = <function1>
    
    scala> summer(1,2,3)
    res0: Int = 6
    

    但不是现在的 2.10,也没有明显的计划来改变这一点:https://issues.scala-lang.org/browse/SI-4176

    Welcome to Scala version 2.10.0-RC2
    (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_31).
    ...
    
    scala> def sum(xs: Int*) = xs.sum
    sum: (xs: Int*)Int
    
    scala> val summer = sum _
    summer: Seq[Int] => Int = <function1>
    
    scala> summer(1,2,3)
    <console>:10: error: too many arguments for method apply:
    (v1: Seq[Int])Int in trait Function1
                  summer(1,2,3)
    

    如果你有 2.9,那么你可以

    scala> def temp(early: Int*)(rest: Int*) = sum((early ++ rest): _*)
    temp: (i: Int, j: Int)(rest: Int*)Int
    
    scala> val presummed = temp(1,2) _
    presummed: Int* => Int = <function1>
    
    scala> presummed(4,5)
    res1: Int = 12
    

    但也许您不应该指望拥有可变参数函数,因为它似乎已被弃用(或至少移到 -Yeta-expand-keeps-star 标志后面,作为 -Y 选项可能无法工作或随时被删除)。

    【讨论】:

    • [Rex Kerr] 谢谢你的回复。函数summer就是sum。我的 gunc0 不是 gunc。它的区别在于 gunc0 有 1(Int) 作为第一个参数(gunc 不是)。函数 temp 有两个 Int args BEFOREHAND。我想要一个我们事先不知道 args.size 的部分函数。问候。
    • 回复不应该出现在答案中——我承认不允许新用户评论他们自己问题的答案是很奇怪的。无论如何,我已经修复了它,所以你不知道你事先有多少个参数。我假设您之后也想拥有一个可变数字。如果没有,请编辑您的问题,以给出您应该能够编写的代码的清晰示例以及答案应该是什么。
    • 感谢您指出歧义。我编辑了最初的问题。
    【解决方案2】:

    我找到的解决方案是组合函数:

    Welcome to Scala version 2.10.0-RC1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).
    ...
    scala> 1 :: (_:Int) :: Nil : Seq[Int]
    res42: Int => Seq[Int] = <function1>
    
    scala> gunc _
    res43: Seq[Int] => Int = <function1>
    
    scala> res42 andThen res43
    res54: Int => Int = <function1>
    
    scala> res54(5)
    res56: Int = 6
    

    【讨论】:

    • 感谢您的回复。但我无法编译你的 cpde... Scala 是哪个版本? scala&gt; res0 andThen res1&lt;console&gt;:11: error: type mismatch;found : Int* =&gt; Intrequired: Seq[Int] =&gt; ?res0 andThen res1
    【解决方案3】:

    也许您不应该指望拥有可变参数函数,因为它似乎已被弃用(或至少移到 -Yeta-expand-keeps-star 标志后面)

    SI-6816 确认弃用,并且在 2016 年 12 月的 Scala 2.12.x 中,PR 5558 明确地消失了 (discussion here)。

    我想要一个我们不知道的偏函数args.size BEFOREHAND

    这似乎仍然不可能(在 Scala 2.12.x 中,2016 年 12 月)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-09
      • 2015-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多