为培训由其他编程语言转到 Ruby 的程序员,写了一些 PPT,其中涉及到了一些函数式编程,反馈还不错,于是抽取出来写了一篇短文。
跳过...请自己 Google
会让你的代码看起来更屌(实际并不... 会让你的工资增加(做梦... 会让你写的程序性能更好(一般来说没差别...
到底有什么好处...请自己 Google
奇偶归一猜想(英语:Collatz conjecture),是指对于每一个正整数,如果它是奇数,则对它乘 3 再加 1,如果它是偶数,则对它除以 2,如此循环,最终都能够得到 1。 如 n = 6,根据上述数式,得出序列 6, 3, 10, 5, 16, 8, 4, 2, 1。(步骤中最高的数是 16,共有 8 个步骤) 如 n = 8,根据上述数式,得出序列 8, 4, 2, 1。(步骤中最高的数是 8,共有 3 个步骤) 如 n = 11,根据上述数式,得出序列 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1。(步骤中最高的数是 52,共有 14 个步骤)
给定一个数组,对这个数组里面的每个数字做奇偶归一操作,找出步骤最多的一个序列,比如输入 [4, 6, 8, 11] 返回 [11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
array 的 << vs +
def f(array)
array << 42
end
def f(array)
array + [42]
end
hash 的 []= vs merge
def f(hash)
hash[:foo] = 42
hash
end
def f(hash)
hash.merge(foo: 42)
end
一个例子,常见其他语言转过来的程序员写的 ruby 代码,将一个数组中的字符串转换成大写输出:
countries = []
["china", "usa"].each do |name|
countries << name.upcase
end
countries # => ["CHINA", "USA"]
依赖了外部变量(countries),同时还对变量做了更新(<<)
函数式编程,使用 map:
countries = ["china", "usa"].map do |name|
name.upcase
end # => ["CHINA", "USA"]
再一个例子,加总数组中字符串长度:
length = 0
["china", "usa"].each do |name|
length += name.length
end
length # => 8
函数式编程,使用 inject:
length = ["china", "usa"].inject(0) do |memo, name|
memo + name.length
end # => 8
还可以使用语法糖,简写方式:
length = ["china", "usa"].map(&:length).inject(0, :+)
了解 Enumerable/Array/Hash 的各种方法:map/inject/select/reject/scan/each/each_pair/each_cons...会让你写出不一样的代码。
另外一个比较好玩的特性,举个例子,我们可以假装发明了操作符前置的中文编程:
计算 = -> method, a, b { a.send method, b }
加 = 计算.curry[:+]
减 = 计算.curry[:-]
乘 = 计算.curry[:*]
除 = 计算.curry[:/]
加[2, 乘[4, 10]] # => 42
加1 = 加.curry[1]
加1[41] # => 42
在 Ruby 里面 proc 调用可以用 proc.call, proc.(), 或者 proc[], 我比较喜欢 proc[] 这种方式。
首先写一个函数,来做奇偶判断对应的操作:
f0 = -> x {x.even? ? x / 2 : x * 3 + 1}
再写个函数,来判断是否到 1,返回序列:
f1 = -> x {x == 1 ? [x] : [x] + f1[f0[x]]}
最后写个函数,将输入的数组做 map,然后取序列最大的:
f2 = -> x {x.map{|e| f1[e]}.max_by{|e| e.size}}
输出:
f2[(10..20).to_a]
=> [18, 9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
你最初写的代码会是怎样?对比一下,是否函数式编程真的体现了”describe what to do, rather than how to do it“