InfoQ

新闻

透视Ruby 1.9的Lambda函数

作者 Werner Schuster 译者 贾晓楠 发布于 2008年1月22日 上午8时8分

社区
Ruby
主题
编程,
领域特定语言,
动态语言,
语言
标签
语言特性,
闭包(Closures)
Ruby的Block块是它的关键特色之一,用块能够写出简明且高度可重用的算法。即使没有别的用处,它至少消弱了人们对循环敬畏的态度。这个概念在其他语言和理论中还被称为: 

这是个十分令人迷惑的词汇,因为闭包这个词汇还指对代码作用域的捕获。而块则不需要捕获这个作用域——例如下面的代码     

x = lambda {|x,y| x + y}

没有使用自由变量没有绑定的变量;参数列表中正式声明x和y),因此无须创建一个闭包。

块在其他语言中有很多种多样的表现形式,有的简洁有的冗长。比如对Ruby影响深远的LISP语言,所使用的块语法为:    

(lambda (arg) "hello world")

对Ruby的设计产生影响的另一种语言Smalltalk,采用方括号来简洁地表达语法: 

[arg| ^"hello world"]

Ruby中,块的最方便也最常使用的语法是作为函数的参数。它允许简单地在函数名后面添加一个用do/end 或者花括号{ / }包围的代码块。例如:

5.times {|x| puts x}

这非常的方便,同时也产生了Builder这样的习惯性用法。Builder可以通过嵌套的块来很容易地创建分层的数据结构。提示:就在一月下旬InfoQ即将发表一篇详细描述如何在Ruby中创建Builder的文章)。

不过,还有一个问题:要传递一个以上的块给函数或方法就没那么简单了。它可以实现,但不能用这么短的语法,得使用Proc.new {}lambda {} 来创建块。虽然还不至于恐怖,但这样会使代码冗长,而且还引入了一些不受欢迎的词汇把代码搞得凌乱不堪。(注意:Proc.new {} 和 lambda {}也有些微妙的不同,但本文不关注它们)。

在特定情况下可能变通的方法。例如,如果一个API调用需要多个块,辅助函数就会嵌入到类中,这样就产生了两个作用:a) 辅助了块 b) 带有貌似命名参数的负作用:

find (predicate {|x,y| x < y}, predicate{|x,y| x > 20})

其中predicate函数仅仅是:

def predicate(&b)
 b
end
它用来返回这个块。不论这是否合适或者不依赖于特定情况。在这种情况下,下面的代码——毋庸置疑地——更能表达清楚,也能起到相同的作用。
find (lambda{|x,y| x < y}, lambda {|x,y| x > 20})

为什么呢?因为lambda泄露了实现它的细节——若带有一个块参数,就不需要额外的关键词。predicate的解决方案对代码做了注解,产生了lambda。需要明确的是,这只是变通的方法

现在,Ruby 1.9引入了一个新的、更简洁的语法来创建lambda函数

  x = ->{puts "Hello Lambda"}

新的语法更加简短,还抛弃了那个不知所云的术语lambda。需要明确的是,这是个语法糖衣。不过它的确有助于写出可读性非常好的API代码。中一些API可以被称为“内部DSLs”,尽管它们的定义都很模糊。出于这些,新的lambda定义帮我们摆脱了那个夹在要么是纯领域要么是问题确定的代码中间的晦涩的术语“lambda”。

Sidu Ponnappa报告了1.9中另外一个语法变化:

在Ruby 1.9.0中,在一个块内显式调用另一个块。在上一篇帖子中我没有提到这个方法,因为解析器一遇到|*args, &block|时就会工作失常。代码如下:[..]

class SandBox
 def abc(*args)
  yield(*args)
end
define_method :xyz do
 |*args, &block|
 block.call(*args)
 end
end
SandBox.new.abc(1,2,3){|*args| p args} # => [1, 2, 3]

这段代码在Ruby 1.8.x下无法运行——它在解析阶段就失败了:

benchmark3.rb:8: syntax error, unexpected ',', expecting '|' 
define_method :xyz do |*args, &block|
 ^
benchmark3.rb:11: syntax error, unexpected kEND, expecting $end

在Ruby 1.9中,它可以正常运行。

1.9的另外一个变化就是修复了一个早就发现的问题: 现在块参数局部的了。看这段代码:

foo = "Outer Scope"
[1,2,3].each{|foo|
 foo = "I'm not local to this block"
}
puts foo

在1.8中,这段代码会输出"I'm not local to this block",而在1.9中,输出为"Outer Scope"。简而言之,现在块像我们期望的那样工作了:块参数遮住了块外的同名变量。(我们先来问自己一个问题:“如何访问外部域的变量”。你不能—— 仅为块参数选择一个不同的名字)。

你怎么看Ruby 1.9中lambda和块的变化?它们涉及了我们一直关注的问题了吗?还有没有遗留的问题?

提示: 查看InfoQ上所有Ruby 1.9相关的文章。 

查看英文原文:The state of the Lambda in Ruby 1.9

不错 发表人 a x 发表于 2008年10月28日 下午7时51分
  1. 返回顶部

    不错

    2008年10月28日 下午7时51分 发表人 a x

    相对‘lambda’而言,我也喜欢->这个符号~

深度内容

和Google互补的搜索引擎Wolfram|Alpha

Wolfram|Alpha与Google究竟是什么关系,Wolfram|Alpha自己是如何定位的?Wolfram|Alaph在多大程度上是语义网搜索呢?InfoQ中文站就等等这些问题采访了Wolfram研究公司中国区商务经理王翔。

SOA契约成熟度模型

本文说明了所推荐的契约版本管理设计策略是如何与SOA成熟度模型发生联系的。文章目的是为实现版本管理和可组合性提供一个路线图。

数据服务简介

Vijay Narayanan在这篇文章中对数据服务的几个方面进行了介绍,它们都是SOA实践者和数据架构师感兴趣的内容。本文对数据服务的几个方面进行了介绍,包括需求定义,基本原理和好处、范围、开发以及消费模式。

分块云计算

在本文中,Jimmy Nilsson描述了一种他在过去数年间观察到的一种正在缓慢成长的架构风格,他把这种风格称为“分块云计算”。

豆瓣网技术架构变迁

罗马不是一天建成的,豆瓣的技术架构也是随着用户规模的增长一直在持续变化中。在本次演讲中,豆瓣的首席架构师洪强宁将与大家一起分享从上线时的单台服务器架构开始一直到现在的豆瓣架构变迁历程。

融合思想:深入探索S#arp架构

Billy McCafferty展示了S#arp架构,它在ASP.NET MVC框架的基础上,荟萃了当今的最佳实践,应用在ASP.NET Web应用程序的架构设计中。

王雷谈开源以及新兴市场计划

中国作为新兴市场中的新兴市场,是Sun在美国之外实施SSE(SUN Startup Essentials)项目重点关注的地区。在QCon Beijing 2009期间,InfoQ中文站有幸对此项目的负责人王雷先生进行了采访,探讨了关于开源、新兴市场、SSE等话题。

使用HTML5构建下一代的Web Form

HTML5 是由 WHATWG发起的,最开始的名称叫做Web Application 1.0,而后这个标准吸纳了Web Forms 2.0的标准,并一同被W3C组织所采用,合并成为下一代的HTML5标准。