【问题标题】:Curried function in scalascala中的咖喱函数
【发布时间】:2013-08-26 06:05:35
【问题描述】:

我有下一个方法的定义:

def add1(x: Int, y: Int) = x + y

def add2(x: Int)(y: Int) = x + y

第二个是第一个的咖喱版本。然后,如果我想部分应用第二个函数,我必须写 val res2 = add2(2) _。一切顺利。接下来我想对 add1 函数进行柯里化。我写

val curriedAdd = (add1 _).curried

curriedAdd 与add2 相似,我说得对吗? 但是,当我尝试以 val resCurried = curriedAdd(4) _ 的这种方式部分应用 curriedAdd 时,会出现编译错误。然后我将其修复为

val resCurried = curriedAdd(4)

为什么Functions.curried 的结果与添加函数的咖喱版本不同(来自add2)?

【问题讨论】:

    标签: scala currying


    【解决方案1】:

    要回答这个问题,我们来看看 REPL。

    首先我们像你一样定义这两个函数。

    scala> def add1(x: Int, y: Int) = x + y
    add1: (x: Int, y: Int)Int
    
    scala> def add2(x: Int)(y: Int) = x + y
    add2: (x: Int)(y: Int)Int
    

    我们定义了两个函数。第一个期望在一个参数列表中有两个参数。第二个需要两个参数,每个参数都在自己的参数列表中。结果类型相同。
    让我们继续。

    scala> val curriedAdd = (add1 _).curried
    curriedAdd: Int => (Int => Int) = <function1>
    

    您刚刚创建了一个部分应用函数,它需要 一个 参数并返回一个 Int =&gt; Int 类型的部分应用函数。这不像您期望的那样类似于add2
    要为add2 实现相同的效果,您需要调用

    scala> val curriedAdd2 = add2 _
    curriedAdd2: Int => (Int => Int) = <function1>
    

    【讨论】:

    • 这没有回答问题。 curriedAdd(4) _ 不起作用,但 val i = curriedAdd(4); i _ 起作用。
    • 问题是:“为什么 Functions.curried 的结果与 add 函数(来自 add2)的 curried 版本不同?”我想我指出了不同之处。
    【解决方案2】:

    首先curriedAddadd2 _ 相同,而不是add2。 add2 只是一种方法。

    scala> curriedAdd
    res52: Int => (Int => Int) = <function1>
    
    scala> add2 _
    res53: Int => (Int => Int) = <function1>
    

    关于第二个问题。我认为原因如下。正在做

    scala> val i = curriedAdd(23)
    i: Int => Int = <function1>
    
    scala> i _
    res54: () => Int => Int = <function0>
    
    scala> curriedAdd(23) _
    <console>:10: error: _ must follow method; cannot follow Int => Int
                  curriedAdd(23) _
    

    curriedAdd(23) _ 不起作用。让我们看看 scala 手册(§6.7)-

    如果 e 是方法类型或者如果 e 是一个 按名称调用参数。如果 e 是带参数的方法,则 e _ 表示 e 通过 eta 扩展(第 6.26.5 节)转换为函数类型。 如果 e 是类型为 =>T 的无参数方法或按名称调用参数, e _ 表示 () => T 类型的函数,它在何时计算 e 它应用于空参数列表()。

    记住它只评估它是 method 还是 call-by-name 参数。在curriedAdd(23) _ 中,它不会评估 curriedAdd(23),但会检查它是方法还是名称调用。它不是一个方法,也不是一个 call-by-name 参数。

    它不是 by-name 因为 by-name 是变量的属性。上面你在评估curriedAdd(23) 后得到一个by-name 参数,但curriedAdd(23) 本身不是一个by-name 变量。因此错误(理想情况下编译器应该已经隐藏它)。请注意,以下工作:

    scala> curriedAdd(23)
    res80: Int => Int = <function1>
    
    scala> res80 _
    res81: () => Int => Int = <function0>
    

    上述方法有效,因为res80 _,在这里您将_ 应用于按名称调用 参数并因此进行转换。

    【讨论】:

      猜你喜欢
      • 2011-04-21
      • 2016-10-20
      • 1970-01-01
      • 2014-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多