【问题标题】:Why do curried functions require external parameter names?为什么柯里化函数需要外部参数名称?
【发布时间】:2014-06-11 19:19:11
【问题描述】:

鉴于这个简单的柯里化函数:

func foo(x:Int)(y:Int)->String{
  return "\(x) with \(y)"
}

我希望能够做这样的事情:

let bar = foo(1)
bar(2) //<- error: Missing argument label 'y:' in call

如果我将调用标记为bar(如bar(y:2)),一切正常。但我不明白为什么需要参数名称。有什么办法可以避免吗?

显而易见的事情:

func foo(x:Int)(_ y:Int)-&gt;String ...

似乎不起作用。

【问题讨论】:

  • 不错!顶级 func 和类方法都存在此问题。
  • 是的;甚至 Swift 书中的柯里化示例也显示了这一点(将其粘贴,删除第二个“手动”柯里化函数,您会得到“在调用中缺少参数标签 'b:'”)
  • 把它写成 rdar://17359591。请随意欺骗。

标签: swift currying


【解决方案1】:

这是一个错误,您应该在bugreport.apple.com 提交雷达

作为确认,如果你加下划线,像这样

func foo(x: Int)(_ y: Int) -> String

你会收到警告

参数中的多余“_”:“y”没有关键字参数名称

所以它明确表示y 没有外部名称,但在调用时仍然需要一个,这显然违反了语言规范。

【讨论】:

    【解决方案2】:

    我认为这是一个编译器错误,您的示例应该按照 The Swift Programming Language 书中的描述工作,其中他们提到声明 curried 函数:

    func addTwoNumbers(a: Int)(b: Int) -> Int {
        return a + b
    }
    
    addTwoNumbers(4)(5) // Returns 9
    

    https://bugreport.apple.com

    很好的发现!

    【讨论】:

      【解决方案3】:

      我不确定我是否完全理解你的柯里化。这是我的看法。我有一个函数 foo 如下:

      func foo(x:Int, y:Int) -> String{
        return "\(x) with \(y)"
      }
      
      let bar = foo(1, 2) // gives "1 with 2"
      

      我希望 curry 这个函数来“修复”x 的值,所以按如下方式操作:

      func fooCurry(x:Int) -> (Int -> String) {
        func curry(y:Int) -> String {
          return foo(x, y)
        }
        return curry
      }
      

      上面返回一个新函数,可以如下使用:

      let curriedFoo = fooCurry(1)
      let barWithCurry = curriedFoo(2) // gives "1 with 2"
      

      fooCurry返回的函数有(Int -&gt; String)的签名,表示该参数没有外部名称。

      【讨论】:

      • 您在这里所做的基本上是“手动”柯里化。 func foo(x: Int)(y: Int) -&gt; String 应该作为语言功能开箱即用,但它没有。
      【解决方案4】:

      不是最好的语法,但如果你想暂时绕过它,你可以使用以下基本的柯里化函数:

      func foo(x:Int) -> Int -> String {
        return {
          return "\(x) with \($0)"
        }
      }
      

      那么你可以这样做:

      let bar = foo(1)
      bar(2) //-> 1 with 2
      

      现在显然,当您想编写一个用于管道四个Ints 的柯里化函数时,这个问题就变得很明显了:

      func makerAdders(a:Int)(b:Int)(c:Int)(d:Int) {...}
      

      变成这样:

      func add(a:Int) -> Int -> Int -> Int -> Int {
        return { 
          b in return {
            c in return {
              d in return a + b + c + d 
            }
          }
        }
      }
      

      内部闭包使它比使用内部函数好一点,但它再次破坏了漂亮的func add(a:Int)(b:Int)(c:Int)(d:Int) {return a+b+c+d} 语法的目的。

      【讨论】:

        【解决方案5】:

        据我所知,这绝对是编译器中的一个错误。在它修复之前,您可以使用这些函数获得任何函数的正确柯里化版本(请注意,我已经包含了两个和三个参数的案例,请随意扩展:

        func curry<A,B,C>(f: (A, B) -> C) -> A -> B -> C {
            return { a in { b in return f(a,b) } }
        }
        
        func curry<A,B,C,D>(f: (A, B, C) -> D) -> A -> B -> C -> D {
            return { a in { b in { c in return f(a,b,c) } } }
        }
        

        只需使用:

        curry(addTwoNumbers)(1)(2)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-03-26
          • 1970-01-01
          • 2014-07-25
          • 2011-12-26
          • 2016-01-01
          • 2015-08-25
          • 1970-01-01
          相关资源
          最近更新 更多