Python Ruby中的第一类函数

Python Ruby中的第一类函数,python,ruby,functional-programming,Python,Ruby,Functional Programming,我正在阅读这篇关于函数式编程()的文章,并尝试用Ruby做练习 一个练习定义了两个函数,零和一。Zero接受一个字符串参数并返回字符串索引1-end如果第一个字符为0,则执行相同的操作,但仅当第一个字符为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

我正在阅读这篇关于函数式编程()的文章,并尝试用Ruby做练习

一个练习定义了两个函数,零和一。Zero接受一个字符串参数并返回字符串索引1-end如果第一个字符为0,则执行相同的操作,但仅当第一个字符为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
这个问题要求您编写一个名为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:])
然而,由于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) } ])
有人能想出比传递或调用lambdas更简洁的方法吗?

你可以这样做

puts rule_sequence('0101', [method(:zero), method(:one), method(:zero)])

顺便说一句,
s[1..(s.length)]
可以写成
s[1..-1]
规则[0]。调用(字符串)
可以写成
规则[0].(字符串)
,我将利用这个练习来展示Ruby是如何支持高阶函数的

让我们后退一步,重写
zero
-
one
函数。 你可以注意到他们有很多共同点。 让我们尝试通过编写一个lambda来利用这一点,该lambda可以同时生成

tail_on_prefix = lambda {|prefix|
  lambda {|str| str[1..-1] if str[0] == prefix}
}
我们现在可以轻松定义
0
1

zero = tail_on_prefix.("0")
one = tail_on_prefix.("1")
现在开始执行规则序列

rule_sequence = lambda {|str, rules|
  if (str.nil? or rules.empty?)
    str
  else
    rule_sequence.(rules[0].(str), rules[1..-1])
  end
}
现在调用
rule\u sequence
看起来好多了,不是吗

rule_sequence.("100101", [one, zero, zero]) # => "101"

这些不是函数,而是方法。这就是你的全部问题!如果你用函数(Ruby中称为
Proc
s)重做这个练习,它就会工作。就我个人而言,我更喜欢lambda文本语法,而不是将块传递给
Kernel 35; lambda
来创建lambda,但这只是一种风格偏好。它使它们看起来更接近于其他语言中的lambda文本,如ECMAScript、Haskell、C#、Java、Scala、CoffeeScript等。一个微小的优势可能是,作为内置语法,编译器可能会执行一些优化,这是类似于
lambda
的方法所无法执行的,毕竟,可能会被重写或修改以执行完全不同的操作…但是,我不知道是否有任何现有(甚至未来)编译器会这样做。如果s[0]==p},您可以将函数定义为
tail_on_prefix=->(p,s){s[1..-1],而不是嵌套的
lambda
调用
并用于获取
零和
一,即
one=strip_prefix.curry['1']