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

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

我是一个 Ruby 初学者,目前正在努力寻找一种合适的方法来编写函数式 Ruby,就像我们在 JavaScript 中所做的那样。在 JavaScript 中,开发人员可以编写一个嵌套函数,该函数 returns 允许他们从通用函数创建更具体的函数的函数。哪个看起来:

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 开发人员可以从函数 memberwiseOperate 中创建一个函数 memberwiseModBy10。他们还可以根据需要从 memberwiseOperate 创建尽可能多的其他成员操作函数。但我发现这很难在 Ruby.

中做同样的事情

如何在 Ruby 中编写函数构建函数来实现与上述 JavaScript 代码类似的功能?就像:

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

我可以在其中从 memberwiseOperate 创建一个函数,就像 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中你可以使用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 中,函数不是第一个 class 公民。你不能传递它们。但是,您可以传递 lambda 和 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. return 在 lambda 中 returns 到调用者而 return 在 Proc returns 中来自调用函数。
  2. lambda 检查 Proc 不检查的参数数量。

出于这个原因,您应该默认使用 lambda,因为它将提供最不意外的路径。 有关 Procs、lambda 和块的更深入的文章,请阅读 this article

在 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 转换为块使用一元前缀 & 运算符。