Dart中的函数式编程

标签: 图书推荐 函数式编程 | 发表时间:2013-01-08 16:27 | 作者:baiyuzhong
出处:http://www.programmer.com.cn

JavaScript的一个特点是它支持函数式编程。因为Dart的目标是让人感觉熟悉,现在让我们看看在Dart语言中函数式编程是什么样的。

我们先从一个传统的例子开始,计算斐波纳契数列。在JavaScript中,大概像下面这样写:

function fib(i) {

if (i < 2) return i;

return fib(i-2) + fib(i-1);

}

探索一个语言的函数式编程特性,斐波纳契数列是个很好的例子。不仅因为它是一个函数,也因为它的递归性质可以展示函数的调用。

我不想纠缠于描述递归或者这个函数的细节。相反,让我们关注如何在JavaScript中使用这个函数。

fib(1) // => 1

fib(3) // => 2

fib(10) // => 55

看得出JavaScript函数足够简单。首先是function关键字,然后是函数名,跟着是圆括号中的参数列表,最后是描述函数体的代码块。

那么,等价的Dart语言版本是什么样呢?

// Dart

fib(i) {

if (i < 2) return i;

return fib(i-2) + fib(i-1);

}

等一下,这和JavaScript的版本有什么不同吗?

function fib(i) {

if (i < 2) return i;

return fib(i-2) + fib(i-1);

}

细心的读者会注意到,Dart版本缺少function关键字。除了这一点,两个函数是完全相同的,调用方式也一样。

fib(1); // => 1

fib(5); // => 5

fib(10); // => 55

如果没有其他区别,可以看出Dart语言的设计者确实让这门语言让人感觉很熟悉。

匿名函数

有经验的JavaScript程序员非常精通于使用匿名函数。因为在JavaScript中函数是顶级概念,函数可以在JavaScript中任意传递。甚至某些框架成了回调函数的地域,但是撇开审美不说,没有人会否认匿名函数是JavaScript中的一个重要部分。那么,在Dart中也一定是这样的,对吗?

在JavaScript中,匿名函数省略了函数名,仅使用function关键字。

 function(i) {

if (i < 2) return i;

return fib(i-2) + fib(i-1);

}

我们已经看到JavaScript和Dart的函数仅有的差异是后者没有function关键字。事实证明,这也是二者在匿名函数上仅有的差异。

 (i) {

if (i < 2) return i;

return fib(i-2) + fib(i-1);

}

乍一看,这看起来很奇怪,感觉光秃秃的。但是,这仅仅是从JavaScript的角度来看。Ruby中有比较类似的lambda和Proc。

 { |i| $stderr.puts i }

认真地考虑一下,在JavaScript中function关键字真正起了什么作用?下意识的反应是,它有助于标识出匿名函数,但在实践中,这仅仅是一个干扰。

考虑下面这个显示斐波纳契数值的代码:

var list = [1, 5, 8, 10];

list.forEach(function(i) {fib_printer(i)});

function fib_printer(i) {

console.log(“Fib(“ + i + ”): ” + fib(i));

}

function fib(i) {

if (i < 2) return i;

return fib(i-2) + fib(i-1);

}

function关键字对代码的可读性有帮助还是有阻碍?显然,这使情况变得更糟,尤其是在foreach()调用的内部。

让我们考虑以下等价的Dart代码。

 var list = [1, 5, 8, 10];

list.forEach((i) {fib_printer(i);});

fib_printer(i) {

print(“Fib($i): ${fib(i)}”);

}

fib(i) {

if (i < 2) return i;

return fib(i-2) + fib(i-1);

}

我们所做的只是删除了function关键字,但是代码的意图更清晰了。如果这种效果贯穿于整个项目,那么将显著提升代码库的长期健康。

说到清晰,如果你嫌大括号麻烦,对于简单的函数还有一种更酷的语法。这个迭代语句中的匿名函数(i) {fib_printer(i);}可以写成(i) => fib_printer(i)。这样,我们的代码就变成了下面这样:

var list = [1, 5, 8, 10];

list.forEach((i) => fib_printer(i));

fib_printer(i) {

print(“Fib($i): ${fib(i)}”);

}

fib(i) {

if (i < 2) return i;

return fib(i-2) + fib(i-1);

}

参数(i)在匿名函数的定义和fib_printer(i)调用中重复出现了。在JavaScript中,没有更清晰的做法了。然而在Dart中,函数(i) => fib_printer(i) 可以进一步被简化为简单的fib_printer。

var list = [1, 5, 8, 10];

list.forEach(fib_printer);

fib_printer(i) {

print(“Fib($i): ${fib(i)}”);

}

fib(i) {

if (i < 2) return i;

return fib(i-2) + fib(i-1);

}

在这段Dart代码中,这么用确实很简短。

一阶函数

像前面的forEach()方法那样,这种把匿名函数传递到迭代方法中的行为,已经展示出了函数作为头等公民的良好支持,也就是说,可以把函数像变量一样进行赋值和传递。

在写作本书时,Dart语言还缺少一些功能(例如反射)来支持复杂的函数式概念,如curry化或组合(combinator)。不过,在Dart中已经可以执行偏函数应用(partial function application)了。

偏函数应用的典型示例是把一个对3个数字求和的函数转化为固定了其中的一个数字的函数。

add(x, y, z) {

return x + y + z;

}

makeAdder2(fn, arg1) {

return (y, z) {

return fn(arg1, y, z);

};

}

var add10 = makeAdder2(add, 10);

偏函数应用这个名字来自于返回一个已经应用了一个参数的函数。在这里,makeAdder2这个函数返回另外一个接收两个参数的函数。调用这个新函数的结果与调用第一个参数固定为arg1的原函数的结果一样。

在这里,add10()函数接收两个数字参数,对它们求和,再加上10。

add10(1,1); // => 12

可选参数

在JavaScript应用中更繁琐的事情之一是提取可选参数。在Dart语言中使用内建的语法来封装这个概念,解决了这一问题。

像下面这样,把可选参数放在方括号中:

f(a, {b1:’who’, b2, b3, b4, b5, b6, b7}) {

// …

}

可以完全不用任何可选参数来调用这个函数:f(‘foo’)。在这种情况下,函数体中的参数a将被赋值为‘foo’。

要指定可选参数,需要在函数调用中给它们加上参数名作为前缀。

f(‘foo’, b6:’bar’, b3:’baz’);

调用前面这个函数的结果是,在f()方法中,变量a赋值为‘foo’,b1是 ’who’,b3是’baz’,b6是‘bar’。所有其他可选参数b2、b4、b5和b7都是null。

这里要特别注意的是,我们可以在函数参数列表中指定可选参数的默认值。在这个例子中,变量b1的默认值是字符串 ’who’ 。

本文节选自《Dart语言程序设计》一书。斯特罗姆著,由人民邮电出版社出版。

相关 [dart 函数 编程] 推荐:

Dart中的函数式编程

- - 技术改变世界 创新驱动中国 - 《程序员》官网
JavaScript的一个特点是它支持函数式编程. 因为Dart的目标是让人感觉熟悉,现在让我们看看在Dart语言中函数式编程是什么样的. 我们先从一个传统的例子开始,计算斐波纳契数列. 在JavaScript中,大概像下面这样写:. 探索一个语言的函数式编程特性,斐波纳契数列是个很好的例子. 不仅因为它是一个函数,也因为它的递归性质可以展示函数的调用.

Google将宣布新编程语言Dart

- 李龑 - Solidot
Google的两位工程师将在下个月举行的Goto软件开发会议上宣布一门全新的编程语言Dart. 这门新语言是为结构化的Web编程设计的,适用于开发基于浏览器的Web应用. Google还没有透露Dart的任何技术细节. Google在2009年曾发布了主要针对服务器端的Go语言.

谷歌宣布推出Dart编程新语言

- Quantum - cnBeta.COM
北京时间9月9日上午消息,据著名科技网站ExtremeTech的报道,谷歌编程新语言Dart逐渐浮出水面,它是一种“结构化的Web编程”语言. 早在几天前谷歌就已着手注册了一系列与Dart相关的域名,当时也引发了沸沸扬扬的猜测.

谷歌宣布推出新的Web编程语言——Dart

- Johnny - ITeye资讯频道
据著名科技网站ExtremeTech的报道,谷歌编程新语言Dart逐渐浮出水面,它是一种“结构化的Web编程”语言. 早在几天前谷歌就已着手注册了一系列与Dart相关的域名,当时也引发了沸沸扬扬的猜测. 此前,Google还向美国专利与商标局提交了名为“SPOT”的商标注册,也引发了Spot为Google的新的编程语言的猜测.

Google宣布结构化编程语言Dart

- Feng - GeekPark 捕风捉影
Google官方博客宣布了新语言Dart. Dart是一种基于类的可选类型化编程语言,设计用于创建Web应用程序. Google称,Dart的设计目标是为Web编程创造结构化但又富有灵活性的语言;编程方法一目了然,符合程序员的自然习惯,易于学习;能在所有浏览器和不同环境中实现高性能. Dart代码以两种方式执行,一种是原生虚拟机,一种是JavaScript引擎,用编译器将Dart代码翻译成JavaScript代码.

Google 正式发布适合打造网页应用的 Dart 编程语言

- Kidwind - 谷奥——探寻谷歌的奥秘
在等待了将近一个月之后,Google正式正式发布了Dart语言,帮助你打造网页应用. 这个新的平台可适合开发简单、高效而具有可扩展的网页应用,整合了强大的全新的编程特色,但却同时具备你熟悉的语言语法结构. Google称这个新的语言将协助开发者打造出结构化的灵活网页程序,同时Dart又让程序员感到很熟悉而自然,简单易学.

函数式编程初探

- - 博客 - 伯乐在线
诞生50多年之后, 函数式编程(functional programming)开始获得越来越多的关注. 不仅最古老的函数式语言Lisp重获青春,而且新的函数式语言 层出不穷,比如Erlang、clojure、Scala、F#等等. 目前最当红的Python、Ruby、Javascript,对函数式编程的支持都 很强,就连老牌的面向对象的Java、面向过程的PHP,都忙不迭地加入对匿名函数的支持.

Google Dart语言分析

- Jack - Solidot
Google最新推出的Dart语言引发了热议. 它是一种适合服务器端和客户端应用程序开发的程序语言. InfoQ的一篇分析文章认为,Dart的一些特性解决了Java或Javascript语言长期以来没有解决的问题. 它的Snapshots特性类似Smalltalk images,允许应用程序即时启动.