Dre*_*nmi 6 ruby functional-programming currying
假设我有一个泛型Proc,Lambda或者method它带有一个可选的第二个参数:
pow = -> (base, exp: 2) { base**exp }
Run Code Online (Sandbox Code Playgroud)
现在我想巴结这个功能,给它一个exp的3.
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.
如何用第二个参数来讨论函数?
您可以构建自己的关键字风格的咖喱方法,该方法收集关键字参数,直到存在所需的参数.就像是:
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)
上面的示例仅限于关键字参数,但您可以扩展它以支持关键字参数和位置参数.
我不认为你可以做到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)