新手问题 求教 ruby 编程语言一书中关于函数式编程的问题

p_next · 2013年07月23日 · 最后由 blackanger 回复于 2013年07月23日 · 2995 次阅读
module Func
  # 如此调用
  # a = [[1, 2], [3, 4]]
  # sum = lambda { |x, y| x + y }
  # sums = sum|a  # => [3, 7]
  def apply(enum)
    enum.map &self
  end

  alias | apply
end

class Proc; include Func; end
class Method; include Func; end

请问:1、enum.map &self 这句话怎么理解?self 按书上调用例子看应该是一个 lambda,那么&self 是个什么意思? 2、sum|a是什么意思? 3、|是一个方法名称,那么调用它的时候应该是 接受者.|(args),为何把.给省略了?

quite confusing. 谢谢大家!!

enum.map &self 对 enum 每一个元素调用自身(此时自身通常是一个 Proc)。 看这个例子:

enum = [1,2,3,4].each
lambda {|x| x + 1}.instance_exec {enum.map &self} # => [2,3,4,5]

sum | a表示 sum 重定义了|运算符。LZ 可以自行学习 Ruby 的运算符重载部分。

#1 楼 @iBachue 感谢感谢!!运算符重载懂了,enum.map &self 的原理通过前辈的例子也基本懂了。

不过还是有个细节有问题,书上那个例子里面,enum.map 第一次循环应该是获得了[1, 2] 那么这个一维数组 传给 lambda 是不是不合适?

#2 楼 @p_next 没有不合适,lambda 此时表现与 proc 基本一致,传入数组就会将里面的元素一一赋值给各个参数

&self 就是调用 self.to_proc

首先,这段代码只能运行在 ruby1.8 环境下。 这段代码的目的是为了求解一个二维数组里面的值,根据给定函数(那个 lambda)的不同,而得出相应的结果。

比如我们可以制定 sum = lambda{|x, y| x*y}

这样可能行为像一个数学函数:

f(x)= y

那个 sum 就相当于f(x, y) = x + y

这是函数式编程里面的高阶函数,在 Ruby 里面就是 lambda,当然也有其他闭包表现形式。

然后看 module 里面的那个 apply 方法,他是利用了 map 方法,map 方法给定一个块参数, &self, 这个时候块参数&self 必须是一个 Proc 对象,而你必须搞清楚这个时候 self 是什么,这个 self,是消息 receiver,就是 sum | a 时候的 sum,相当于:

a.map &self

展开就是

a.map{ |x, y| x + y}

这个方法楼主应该明白吧?

而下面的模块 include,是为了让每一个 Proc 对象和 Method 对象可以拥有 | 方法。当然 alias 是给方法定义别名,也就是 apply 方法。关于你问的第 3 个问题,1 楼说的对,相当于你重载了操作符|,当你使用 | 的符号,Ruby 会找之前的 | 操作符,结果你使用 alias 给重载了,所以sum | a这里没有用点来调用。

class Proc; include Func; end class Method; include Func; end

在 Ruby2.0 里面,应该这么用:

a = [[1,2], [3,4]] sum = ->(a){ a[0] + a[1]} #ruby2.0里lambda写法

sums = sum | a

因为在 ruby2.0 里面,sum = ->(a,b){ a + b} 这种写法,你如果传过来一个数组,就会认为是一个参数,会报参数个数错误的。类似 ([1, 2]){a + b}这样。

具体关于 ruby 的 block,可以参考我的视频教程: http://edu.51cto.com/course/course_id-418.html

#4 楼 @zhangyuan &self 不是调用 to_proc, 你可能记成了符号 map(&:to_i) 这种用法。在这个例子里:

sum = ->(a){a[0] + a[1]} 是个 lambda,已经是一个 Proc 对象,根本不需要调用什么 to_proc, 像&:to_i 这种写法,是因为符号类型作为块参数传递,需要把它转化为一个 Proc,所以才要调用 to_proc.

楼主的这个例子,在 map 方法内部,执行的是 proc.call 被调用,所以在 ruby2.0 中会报一个参数个数错误的异常。

#5 楼 @blackanger 这么详细。。。惊呆了

#7 楼 @small_fish__ 哈哈,今天正好有空。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号