Ruby 中的一流函数

Jos*_*ack 5 ruby python functional-programming

我正在阅读这篇关于函数式编程的文章(https://codewords.recurse.com/issues/one/an-introduction-to-function-programming),并尝试在 Ruby 中进行练习。

一项练习定义了两个函数:零和一。Zero 接受一个字符串参数,如果第一个字符为 0,则返回字符串索引 1 - end;One 执行相同的操作,但前提是第一个字符为 1。

以下是 ruby​​ 实现:

def zero(s)
  if s[0] == "0"
    return s[1..(s.length)]
  end
end

def one(s)
  if s[0] == "1"
    return s[1..(s.length)]
  end
end
Run Code Online (Sandbox Code Playgroud)

该问题要求您编写一个名为rule_sequence的方法,给定一个字符串和一个函数数组,返回结果,以便一次调用一个函数——第一个函数在整个字符串中调用,第二个函数被调用该字符串的返回值等。如果在任何时候,其中一个函数返回 nil,则返回 nil。

Python 的实现是:

def rule_sequence(s, rules):
    if s == None or not rules:
        return s
    else:
        return rule_sequence(rules[0](s), rules[1:])
Run Code Online (Sandbox Code Playgroud)

然而,由于 Ruby 似乎不支持高阶函数,所以我能想到的最优雅的解决方案如下:

def rule_sequence(string, rules)
  if rules.length == 0 or string.nil?
    return string
  else
    return rule_sequence(rules[0].call(string), rules[1..rules.length])
  end
end

puts rule_sequence('0101', [lambda { |s| zero(s) }, lambda { |s| one(s) }, lambda { |s| zero(s) } ])
Run Code Online (Sandbox Code Playgroud)

有人能想出比传递或调用 lambda 更简洁的方法吗?

小智 7

我将以此练习为契机来展示 Ruby 如何支持高阶函数。

让我们退后一步,重写zero-one函数。你会发现他们有很多共同点。让我们尝试通过编写一个可以生成两者的 lambda 来利用这一点

tail_on_prefix = lambda {|prefix|
  lambda {|str| str[1..-1] if str[0] == prefix}
}
Run Code Online (Sandbox Code Playgroud)

我们现在可以轻松定义zero和one

zero = tail_on_prefix.("0")
one = tail_on_prefix.("1")
Run Code Online (Sandbox Code Playgroud)

到rule_sequence现在!

rule_sequence = lambda {|str, rules|
  if (str.nil? or rules.empty?)
    str
  else
    rule_sequence.(rules[0].(str), rules[1..-1])
  end
}
Run Code Online (Sandbox Code Playgroud)

现在打电话rule_sequence看起来好一点了,不是吗

rule_sequence.("100101", [one, zero, zero]) # => "101"
Run Code Online (Sandbox Code Playgroud)