如何像在JavaScript中一样用Ruby编写函数构建函数

How to write a function-building function in Ruby just like in JavaScript?

本文关键字:函数 一样 Ruby 构建 何像 JavaScript      更新时间:2023-12-24

我是一名Ruby初学者,目前正在努力寻找一种合适的方法来编写Functional Ruby,就像我们在JavaScript中一样。在JavaScript中,开发人员可以编写一个嵌套函数,该函数返回一个函数,使他们能够从泛型函数中创建一个更具体的函数。哪个看起来:

function memberwiseOperate(opr){
    return function(array){
        return array.map(opr);
    }
}
var modBy10 = function(a){return a%10} // Make an operator function
var memberwiseModBy10 = memberwiseOperate(modBy10); // Make a specific function from the function-buildinng function
var output1 = memberwiseModBy10([11,12,13,14,15]);
var output2 = memberwiseModBy10([31,32,33]);

从上面的代码中,JS开发人员可以从函数memberwiseCoopere创建一个函数memberwiseModBy10。他们也可以根据自己的意愿从memberwiseCooperte创建任意数量的其他memberwise操作函数。但我发现在Ruby中很难做到这一点。

我如何用Ruby编写一个函数构建函数,实现与上面JavaScript代码类似的功能?就像:

def memberwiseOperate(opr)
    return Proc.new{ |array| array.map(opr) } # return a new function, how?
end

在其中,我可以从memberwiseCooperte创建一个函数,就像JS让我这样做一样:

modBy10 = Proc.new{|a| a%10}
memberwiseModBy10 = memberwiseOperat(modBy10) # Possible to create a function from a function?
output1 = memberwiseModBy10([11,12,13,14,15])
output2 = memberwiseModBy10([31,32,33])

有没有一种可能的方法可以在Ruby中实现这一点?

在Ruby中几乎完全相同。为了更清楚地看到相似之处,让我们首先将代码重写为更现代的ECMAScript:

const memberwiseOperate = opr => array => array.map(opr);
const modBy10 = a => a % 10; // Make an operator function
const memberwiseModBy10 = memberwiseOperate(modBy10); // Make a specific function from the function-building function
const output1 = memberwiseModBy10([11, 12, 13, 14, 15]);
const output2 = memberwiseModBy10([31, 32, 33]);
console.log(output1);

这就是翻译成Ruby时的样子:

memberwise_operate = -> opr { -> array { array.map(&opr) }}
mod_by_10 = -> a { a % 10 } # Make an operator function
memberwise_mod_by_10 = memberwise_operate.(mod_by_10) # Make a specific function from the function-building function
output1 = memberwise_mod_by_10.([11, 12, 13, 14, 15])
output2 = memberwise_mod_by_10.([31, 32, 33])
puts output1

正如您所看到的,几乎唯一的区别是Enumerable#map采用块参数,而不是Proc,因此我们必须使用一元前缀&运算符将Proc转换为块。

在ruby中,您可以使用map并传递块。例如:

array.map { |element| element % 10 }

或者,如果你喜欢:

mod_by_10 = Proc.new { |a| a%10 }
array.map(&mod_by_10)

注意map有两种:

map没有副作用,map!有副作用。

如果我明白你想做什么,那就和一样简单

 a = lambda{|x| x % 10}
 [11,12,13,14,15].map(&a)

在Ruby中,函数不是第一类公民。你不能把它们传来传去。不过,你可以绕过lambdas和Procs。

memberwise_operate = ->(func) { ->(array){ array.map(&func)} }
mod_by_10 = ->(a){ a % 10 }
memberwise_mod_by_10 = memberwise_operate.call(mod_by_10)
memberwise_mod_by_10.call([11,12,13,14,15]) # => [1, 2, 3, 4, 5]
memberwise_mod_by_10.call([31,32,33]) # => [1, 2, 3]

然而,这并不是大多数人编写Ruby的方式。Ruby是一种具有函数元素的面向对象编程语言。

->(param){ puts param }

是的缩写吗

lambda{|param| puts parm }

PS:Proc和lambda:之间有两个显著的区别

  1. lambda中的return返回给调用者,而Proc中的return则从调用函数返回
  2. lambda检查Proc不检查的参数数

出于这个原因,您应该默认为lambda,因为它将为路径提供最少的惊喜。有关Procs、lambdas和blocks问题的更深入的文章,请阅读本文。