使用关键字参数来描述proc

Dre*_*nmi 6 ruby functional-programming currying

假设我有一个泛型Proc,Lambda或者method它带有一个可选的第二个参数:

pow = -> (base, exp: 2) { base**exp }
Run Code Online (Sandbox Code Playgroud)

现在我想巴结这个功能,给它一个exp3.

cube = pow.curry.call(exp: 3)
Run Code Online (Sandbox Code Playgroud)

这里存在歧义,源于关键字参数和新的哈希语法,其中Ruby将其解释exp: 3为作为第一个参数传递的哈希值base.这会导致立即调用该函数,从而将NoMethodErrorwhen #**发送到散列.


为第一个参数设置默认值同样会导致在currying时立即调用该函数,并且如果我根据需要标记第一个参数,而不提供默认值:

pow = -> (base:, exp: 2) { base**exp }
Run Code Online (Sandbox Code Playgroud)

base当我试图讨论时,翻译会抱怨我错过了争论Proc.


如何用第二个参数来讨论函数?

Ste*_*fan 8

您可以构建自己的关键字风格的咖喱方法,该方法收集关键字参数,直到存在所需的参数.就像是:

def kw_curry(method)
  -> (**kw_args) {
    required = method.parameters.select { |type, _| type == :keyreq }
    if required.all? { |_, name| kw_args.has_key?(name) }
      method.call(**kw_args)
    else
      -> (**other_kw_args) { kw_curry(method)[**kw_args, **other_kw_args] }
    end
  }
end

def foo(a:, b:, c: nil)
  { a: a, b: b, c: c }
end

proc = kw_curry(method(:foo))
proc[a: 1]              #=> #<Proc:0x007f9a1c0891f8 (lambda)>
proc[b: 1]              #=> #<Proc:0x007f9a1c088f28 (lambda)>
proc[a: 1, b: 2]        #=> {:a=>1, :b=>2, :c=>nil}
proc[b: 2][a: 1]        #=> {:a=>1, :b=>2, :c=>nil}
proc[a: 1, c: 3][b: 2]  #=> {:a=>1, :b=>2, :c=>3}
Run Code Online (Sandbox Code Playgroud)

上面的示例仅限于关键字参数,但您可以扩展它以支持关键字参数和位置参数.

  • 非常感谢@stefan的示例实现!我也在考虑这些问题,但我打算将它命名为"#scurry".:-P (2认同)

Joh*_*ooy 6

我不认为你可以做到Proc.curry,但总有办法

cube = -> (base) {pow.(base, exp: 3)}
Run Code Online (Sandbox Code Playgroud)

你也可以创建一个工厂函数

pow_factory = -> (exp) {-> (base) {pow.(base, exp: exp)}}
cube = pow_factory.(3)
Run Code Online (Sandbox Code Playgroud)