[Real world Haskell] 中文翻译:前言

前言

做个约定吧!

Haskell是门深刻的语言,学习它将使一个非常有价值的经历。我们集中在三点来解释其原因。首先是新颖:我们请你从一个不同而有价值的视角来看待编程。其次是强大:我们将向你展示如何创建更短更快更安全的软件。最后,可以给你很多乐趣:用美丽的编程技术来解决实际问题的愉悦。

新颖

Haskell很可能与你曾经用过的任何语言都很不同。与程序员脑中通常的概念相比,函数式编程让我们看待软件有一个深刻的不同方式。

在Haskell里,我们不强调修改数据的代码。而是关注于那些取不变值作为输入并输出新值的函数。给出相同的输入,这些函数总是返回相同的输出结果。这是函数式编程的核心思想。

不仅不修改数据,我们的Haskell函数通常不与外界交互;我们称这样的函数为纯函数。我们把纯的代码与那些读写文件的程序严格分开。这更容易组织,验证和测试程序。

我们抛弃了一些可能看上去很基本的想法,如语言中内建 for 循环一类。我们有其他更灵活的方式来做重复的任务。

甚至在Haskell中对表达式求值的方式也是不同的。我们把所有的计算都推迟到其结果真的需要时: Haskell是惰性语言。惰性不只是移动下工作的事:它深刻的影响了我们如何写程序的方式。

强大

在全书各处都会展示Haskell的特性,相对于传统语言是多么强大灵活,他们可以产生更可靠的代码。Haskell确实塞满了如何创建优秀软件的领先思想。

因为纯代码与外部世界没有关系,并且它处理的数据用于不会改变,因此数据被其他程序修改导致隐形冲突的讨厌情况很少见。不管把纯函数用在什么场景中,它的行为总是一致的。

纯代码比处理外部世界的代码更容易测试。当一个函数只对它可见的输入负责时,我们可以很容易断定它行为的属性应该总是一样。我们可以自动用大量随机输入来测试这些属性,测试通过后继续往前走。我们还是用传统的技术来测试必须与文件,网络或者外部硬件进行交互的代码。由于这些非纯的代码比其他传统语言中要少得多,因此对我们的软件的稳固性更有信心。

惰性计算有些令人恐惧的影响。比如说我们想从一个未排序的列表里找出最小的k个元素。在传统语言里明显的方法是,把列表排序,然后取出前
k个元素,但这耗费颇大。为了效率我们不是写个特殊函数来一次取出这些值,而是必须做些适度的簿记工作。在Haskell里,排序并取值的方式实际上工作良好:惰性计算保证了列表只进行足够取出k个最小元素的排序工作。

更好的是,执行如此高效的Haskell代码只有很短,并且使用标准库函数。

-- file: ch00/KMinima.hs
-- lines beginning with "--" are comments.

minima k xs = take k (sort xs)

要建立起何时惰性计算重要的直觉可能要花一点时间,不过当我们使用它时,产生的代码经常更清晰简洁高效。

前面例子显示出,Haskell的强大很重要的一点在于其紧凑的代码上。与流行的传统语言相比,用Haskell开发时经常可以写出更短的代码,所花时间也更少,bug更少。

乐趣

我们相信要掌握Haskell编程的基础很简单,你用几个小时或者几天就可以成功的写些小程序了。

由于在Haskell中高效的编程与其他语言具有很大的不同,因此你要做好准备掌握这门语言本身以及函数式编程技术都将需要大量的思考和实践。


与我们自己开始学习Haskell的早期岁月相比,好消息是现在乐趣来得更早些:钻研一门新的语言并了解如何写出简单的程序只是愉快的挑战,有非常多不同或者缺失的普通概念。

对我门来说,最初的乐趣随着我们经验的增加和理解的深入一直持续着。在其他的语言中很难找到科学与基本编程间的任何联系。在Haskell里我们引入了一些抽象数学的思想并使之实际工作。而且我们发现这些思想不单容易被掌握而且有助于写出更紧凑可复用的代码。

更进一步,我们不会设置任何“高墙”:这本书里并没有特别困难或可怕的技术,不需要掌握他们就可以高效的编程。

有人说Haskell种严密的语言:它让你提前思考更多。在你可以可以运行它之前要对代码花多些时间调试,来处理编译器指出的程序中不合理的地方。一旦修改完编译错误后,我们的Haskell程序经常第一次运行就能正确,即使已经有了多年的经验,我们依然为此感到震惊和喜悦。

对本书的预期

越来越多的人开始用Haskell来解决日常的问题,因此我们开始了这个项目。由于Haskell的学院渊源,现在已经存在的Haskell书籍没有关注我们感兴趣的典型的编程技术的。

这本书里,我们想要向你展示如何使用函数式编程和Haskell来解决实际的问题。我们用手把手的方式:每一章都包含大量的代码例子,很多包含完整的应用。这些是要教你如何开发的库,技术和工具的例子。

* 创建一个软件,从互联网上下载播客段落,把历史记录保存在SQL数据库中。

* 用直觉和强大的方式来测试代码。描述出程序应具有什么属性,然后让 QuickCheck 库自动生成测试案例。

* 把手机摄像头拍下来的条形码转换成标识,可以用它在图书馆或在线书店网站进行查询。

* 编写适用于web的代码。与其他语言写的服务器和客户端用JSON格式交换数据。开发一个并发的链接检查器。

关于读者

读本书之前要先知道什么?我们期望你已经知道如何编程,不过如果你从来没用过函数式语言也没关系。

不管你的水平如何,我们都预先准备好你需要的了;我们尽量深入解释新的微妙的思想,经常配以例子和图片来说明自己的观点。

如果你知道那些库函数或编程技术的话,就可以避免很多手写的代码,不过新的Haskell程序员开始时很难避免。这本书里带了很多信息帮你尽可能的提速。

当然一路上总会有些磕碰。如果动身时做好准备,伴随着乐趣还有偶然的惊奇和困难,你将获得最好的体验。可能遇到的困难都不会持续太久。

当成为更有经验的Haskell程序员时,你写代码的方式会变化。实际上,在本书的课程其间,书里给出的代码也在进化,从语言的基础到强大富有生产力的特性和技术。

对Haskell的预期

Haskell是通用编程语言。被设计的不针对任何特定应用。虽然它对于程序该如何写有很强的立场,不过它并不偏重于某个问题领域。

这门语言的核心鼓励一个纯的惰性的编程风格,这是默认的但并非唯一的选择。Haskell也支持更传统的过程式代码和严格求值模式。另外,虽然这门语言关注于静态类形程序,也是可以(虽然很少见)用动态类型的风格来写Haskell程序。

与传统静态语言的比较

使用简单的静态类型系统的语言已经占据编程世界主导地位几十年了。Haskell是静态类型的,但是它对于类型可以做什么的见解与传统语言相比,要更加灵活强大。类型让Haskell程序更简短,清晰和强大。

尽管很强大,Haskell的类型系统经常可以不引人注目。如果忽略掉显示的类型信息,Haskell编译器将自动推断表达式或函数的类型。传统静态类型语言要喂给编译器非常多的类型信息,与此相比Haskell的类型的能力与推断相结合,显著的减少了代码的凌乱和冗余。

Haskell其他一些特性组合起来,能让代码更加漂亮。这会改善代码的开发时间和敏捷性:我们可以快速的创建可靠的代码,并且在需求变化时能更容易重新掌握代码。

有时候,Haskell程序比用C/C++写的相似的程序运行的慢。对于我们写的大部分代码来说,Haskell的巨大优点在于生产力和可靠性,这些优点超过了任何性能上小的损失。

多核处理器现在很普及了,但是用传统技术非常难以编写多核程序。Haskell为编写更易驾驭的多核程序提供了独特的技术。它支持并行程序,软件事务内存(STM)可以开发可靠的并发程序,可以扩展到成百上千个并发的线程。

与现代动态语言的比较

在过去十年间,动态类型的解释型语言已经变得很流行了。他们提高了开发生产力。虽然这经常会有很大的性能损失的代价,但是对于很多编程任务来说,生产力的重要性要超过性能,或者性能并不是关键因素。

Haskell和动态类型语言在简短性上很相似:解决问题时都比传统语言用更少的代码。动态语言和Haskell的程序经常差不多大小。

当考虑执行型能时,Haskell几乎总是具有巨大的优势。用 Glasgow Haskell编译器(GHC)编译的代码通常比用动态类型语言解释器要快20到60倍。GHC也提供了解释器,因此可以不需要编译,把程序当作脚本执行。

动态类型语言与Haskell对于类型的哲学存在重大不同。动态类型语言流行的一个主要原因是,我们很少需要显示的声明类型。通过自动类型推断,Haskell也提供了相同的优势。

除了表面的相似性,差别更加深刻。在动态类型语言里可以构造出静态类型语言很难表达的结构。然而反之亦然:通过像Haskell那么强大的类型系统,我们可以构造一个动态类型语言难于管理或实现的程序。

两种方式都涉及到交易。简单的说,Haskell的观点强调安全性,而动态类型更偏爱灵活性。如果有人已经发现了一种静态类型总是最好的方式,我们想所有人现在就该了解它。

当然我们这些作者对于哪种交易更有利有自己的观点。我们中的两个作者有很长时间的动态类型编程经验。我们很喜爱用他们工作;现在也在每天使用;不过通常我们更倾向于Haskell。

工业界和开源领域的Haskell
这里是一些用Haskell创建的大型软件系统的例子。有些是开源的,其他是私有产品。

* ASIC 和 FPGA 设计软件 (Lava, Bluespec 公司产品)

* 作曲软件 (Haskore)

* 编译器和编译器相关工具(最著名的 GHC)

* 分布式版本控制 (Darcs)

* Web中间件 (HAppS, Galois公司产品)

下面是截止到2008年底,使用Haskell的公司列表,来源是 Haskell wiki (http://www.haskell.org/haskellwiki/Haskell_in_industry)。

* ABN AMRO
一家跨国银行。在投资业务中使用Haskell衡量金融衍生品组合的风险!(译注:被国有化了)

* Anygma

一家创业公司。使用Haskell开发多媒体内容创作工具。

* Amgen

一家生物科技公司。用Haskell创建数学模型和其他复杂的应用。

* Bluespec
ASIC 和 FPGA设计软件提供商。他们的产品用Haskell开发,他们产品里提供的芯片设计语言受Haskell的影响。

* Eaton

使用Haskell来设计和验证氢气混合动力车辆系统。

编译,调试和性能分析

在实际工作中,一门语言周围的库和工具的生态系统与语言本身同样重要。Haskell在这方面表现很好。

最广翻使用的编译器 GHC 已经活跃的开发了超过15年,并且提供了成熟稳定的特性集。

* 可以编译成现代主要的CPU架构上的本地代码。

* 编译的二进制文件容易部属,没有许可证限制。

* 代码覆盖分析

* 详细的性能和内存使用描述

* 全面的文档

* 对并发和多核扩展性的大量支持

* 交互解释器和调试器

附带的和第三方的库

GHC编译器附带了很多有用的库。这里是满足普通编程需要的库。

* 文件 I/O,以及文件系统遍历和操作。

* 网络客户端和服务器编程

* 正则表达式和解析

* 并发编程

* 自动测试

* 声音和图像

Haskell社区把开源库和软件收集在 Hackage 软件包数据库里。Hackage里发布的大部分库都是自由协议的,允许商用或者开源使用。开源库涵盖的一些领域包括下面这些。

* 与全部主要的开源和商业数据库的接口

* XML, HTML 和 XQuery 处理

* 网络及web的客户端和服务器开发。

* 桌面GUI,包括跨平台库。

* 支持Unicode和其他文本编码

Haskell简史

Haskell开发的起源根植于数学和计算机科学的研究。

史前时代

在现代计算机发明的几十年前,数学家 Alonzo Church (阿隆索.丘奇)发展了一种称为lambda演算(朗姆达演算)的语言。他意图把这种语言当作研究数学基础的工具。第一个意识到编程与lambda演算之间实际联系的人是 John McCarthy,他在1958年发明了Lisp。(译注:John McCarthy 约翰麦卡锡,1971年图灵奖得主)

在20世纪60年代,计算机科学家开始意识到并研究lambda演算的重要性。Peter Landin 和 Christopher Strachey 发展了编程语言的基础思想:如何验证他们的实际行为(操作语义),以及如何理解他们的含义(指称语义)。

在20实际70年代早期,Robin Milner创建了一个名为 ML 的更加严格的函数式编程语言。开发ML是为了帮助自动证明数学定理,后面被用在更平常的计算任务上。

在70年代开始显露出一种新的惰性计算策略。 David Turner 开发了 SASL 和 KRC, Rod Burstall 和 John Darlington 开发了 NPL 和 Hope。 NPL, KRC 和 ML 影响了80年代一些语言的开发,包括 Lazy ML, Clean和Miranda。

古代

到八十年代晚期,惰性函数式语言的研究者们的努力分散在超过一打的语言中。因为担心力量的分散,一些研究者决定成立一个委员会来设计一个共同的语言。经过三年工作,委员会在1990年发布了Haskell 1.0 规范。以非常具有影响力的逻辑学家Haskell Curry的名字命名。

很多人都怀疑“委员会设计”方式,但是Haskell委员会的工作是委员会方式成功的优美实例。他们拿出了一个优雅的经过深思熟虑的语言设计,并且弥合了研究社区的分歧。90年代纷乱的惰性函数式语言中,只有Haskell至今依然实际使用。

自从1990年发表,Haskell语言标准经过了5次修订,最近一次在1998年。已经开发了一些Haskell的实现,其中一些依然活跃的发展中。

在90年代,Haskell有两个主要目的。一方面,他给语言研究者提供了一种稳定的语言,拿来来试验如何让惰性函数式程序更高效。其他研究者研究如何用惰性函数式技术构造程序。还有些用作教学语言。

现代

随着90年代这些基础研究的进行,Haskell依然还是学术事件。社区里的非正式标语是“拼命避免成功!”。外部的人根本没听说过这门语言。实际上,函数式语言这个领域本身就很非著名。

在此其间,主流的编程世界也做了些相对较小的试验:从C编程到C++再到Java。同时程序员们开始用新的更加动态的语言来进行修补。Guido van Rossum 设计了Python;Larry Wall 创建了 Perl; Yukihiro Matsumoto 开发了 Ruby。

随着这些语言开始更广泛的使用,他们传播了一些重要的思想。首先程序员并非不能用富有表达能力的语言工作,实际上他们以此炫耀。其次是快速增长的计算能力的副产品:牺牲一些执行性能来换取程序员生产力的大量提高是明智的。最后,这些语言从函数式编程中借鉴了很多。

在过去的五年里,Haskell成功的从学院的象牙塔中逃离,像Python,Ruby 甚至Javascript那样有名了。现在在开源以及商业领域,这门语言有了生气勃勃快速增长的用户,而研究者们依然继续推动他的性能和表达能力的扩展。

有用的资源

在用Haskell工作时,肯定会遇到一些问题,想找更多资料。这里时一些互联网资源,可以找到很多信息,并与其他Haskell程序员交流。

参考资料

* The Haskell Hierarchical Libraries reference (Haskell库参考)
提供了编译器附带标准库的文档。这是Haskell程序员最宝贵的在线资源。

* Haskell 98 Report
描述了Haskell98语言标准。

* GHC Users's Guide
包含GHC支持扩展的详细文档,以及一些GHC的特性。

* Hoogle 和 Hayoo
Haskell API搜索引擎。可以用名字或者类型搜索函数。

应用程序和库
如果你想为特定任务找一个Haskell库,或者找一个Haskell写的应用程序,从下面的资源中找。

* Haskell 社区

社区维护了一个开源库和应用的中心数据库。名为 Hackage (http://hackage.haskell.org/)。可以让你搜索软件并下载,或者按类别进行浏览。

* Haskell Wiki (http://haskell.org/haskellwiki/Applications_and_libraries)

Haskell Wiki中专门有一节用来描述Haskell库的信息。

Haskell社区

有很多种方式可以接触到其他的Haskell程序员,问问题,看看别人都在讨论什么,或者与别人简单的建立社会网络。

* 搜索社区资源的第一站应该是Haskell的官方网站(http://www.haskell.org)。这个页面上有最近的社区和信息的链接,还有一个很大的活跃维护的wiki。

*
Haskell用户们用了好几个邮件列表,来分主题讨论(http://haskell.org/haskellwiki/Mailing_lists)。这里面最有趣的是 haskell-cafe。那里的气氛轻松友好,专家和大学老师们与黑客和初学者们随便交流。

* 要进行实时聊天,有一个名为 #haskell 的IRC频道,很大很活跃。像 haskell-cafe 一样,虽然有很大量的用户同时在线,那里气氛依然保持友善有益。

* 有很多本地的用户组,聚会,学术工作组等等;这里有个知名的用户组和工作组列表(http://haskell.org/haskellwiki/User_groups)。

* Haskell Weekly News (http://sequence.complete.org)是每周Haskell社区活动简报。可以找到感兴趣的邮件列表话题,新软件的发布等等。

* Haskell社区和活动报告 (http://haskell.org/communities/)收集了人们如何使用Haskell的信息。它已经运行了很多年了,因此提供了了解Haskell过去历史的好方法。

致谢

没有Haskell社区的话,这本书不会存在:无政府主义者们,满怀希望的艺术家们,理论家和工程师们,他们用了20年时间致力于创造一个更好的,没有bug的程序世界。Haskell社区的人在友善与知识深度的接合上是独一无二的。

感谢我们的编辑 Mike Loukides 和 O'Reilly 的产品团队,感谢他们的建议与协助。

Bryan
与John和Don一起工作充满乐趣。他们独立优秀的特质以及可敬的才能使得写作过程非常顺利。

1994年Simon Peyton Jones 在一个贸然给他写信的大学生身上冒了一个险。给他实习的那个夏天是我专业生涯中的亮点。
通过他慷慨,无穷的活力,以及对协作的推动,他感召了整个 Haskell 社群。

我的孩子 Cian 和 Ruairi,总是时刻准备好用好玩有趣的游戏帮我放松。

最后,当然,我亏欠我的妻子Shannon很多,因为她的爱,智慧,以及在这本书长时间的孕育过程中所给予的支持。

John

很高兴可以在这个项目上与 Bryan 和 Don 合作。他们深刻的Haskell知识以及经验非常令人吃惊。我很喜欢我们三个人可以坐在一间屋子里,从开始写超过了一年的时间。

我两岁大的 Jacob也发现使用键盘很好玩,他总是想把我从电脑前拖去,帮他一起在一个50岁高龄的 Underwood 牌打字机上制造噪音。

最重要的是,如果没有我妻子 Terah 的爱,支持与鼓励的话,我可能根本不会参与到这项工程中来。

Don

首先,我要感谢我神奇的同谋们:John和Bryan,为了他们的鼓励,建议以及动力。

我在Galois 公司的同仁们,他们每天在实际项目中使用Haskell。他们提供了频繁的反馈和实例故事,并且帮助确保了浓咖啡的持续供应。

我的博士导师Manuel Chakravarty 以及 PLS研究组,他们给了我鼓励,视野以及活力,他们让我知道了一种严密的函数式的编程方法可以产生奇迹。

最后,感谢Suzie的洞察力,耐心,以及爱。

感谢我们的评论者

我们用开放的方式来写作这本书,当完成一章的草稿就发到我们的网站上。读者就用我们开发的一个web应用来提交反馈。在我们写完这本书的时候,有超过800个人提交了超过7500个评论,很吓人的景象。

我们深深的感激那么多的人志愿帮助改进我们的书。他们的鼓励和热情,让超过15个月的写作过程很愉快。

我们收到的评论的宽度和广度极大的改善了本书的质量。尽管如此,所有的错误与疏忽,当然,都是我们的。

下面每一个人贡献了已收到的全部评论的1%以上。我们要感谢他们如此热心的提供给我们这么多详细的反馈。

Alex Stangl, Andrew Bromage, Brent Yorgey, Bruce Turner, Calvin Smith, David Teller, Henry Lenzi, Jay Scott, John Dorsey, Justin Dressel, Lauri Pesonen, Lennart Augustsson, Luc Duponcheel, Matt Hellige, Michael T. Richter, Peter McLain, Rob deFriesse, Rüdiger Hanke, Tim Chevalier, Tim Stewart, William N. Halchin. No comments

我们也要感激下面这些人,他们每一个至少贡献了0.2%的评论。

Achim Schneider, Adam Jones, Alexander Semenov, Andrew Wagner, Arnar Birgisson, Arthur van Leeuwen, Bartek Ćwikłowski, Bas Kok, Ben Franksen, Björn Buckwalter, Brian Brunswick, Bryn Keller, Chris Holliday, Chris Smith, Dan Scott, Dan Weston, Daniel Larsson, Davide Marchignoli, Derek Elkins, Dirk Ullrich, Doug Kirk, Douglas Silas, Emmanuel Delaborde, Eric Lavigne, Erik Haugen, Erik Jones, Fred Ross, Geoff King, George Moschovitis, Hans van Thiel, Ionuț Arțăriși, Isaac Dupree, Isaac Freeman, Jared Updike, Joe Thornber, Joeri van Eekelen, Joey Hess, Johan Tibell, John Lenz, Josef Svenningsson, Joseph Garvin, Josh Szepietowski, Justin Bailey, Kai Gellien, Kevin Watters, Konrad Hinsen, Lally Singh, Lee Duhem, Luke Palmer, Magnus Therning, Marc DeRosa, Marcus Eskilsson, Mark Lee Smith, Matthew Danish, Matthew Manela, Michael Vanier, Mike Brauwerman, Neil Mitchell, Nick Seow, Pat Rondon, Raynor Vliegendhart, Richard Smith, Runar Bjarnason, Ryan W. Porter, Salvatore Insalaco, Sean Brewer, Sebastian Sylvan, Sebastien Bocq, Sengan Baring-Gould, Serge Le Huitouze, Shahbaz Chaudhary, Shawn M Moore, Tom Tschetter, Valery V. Vorotyntsev, Will Newton, Wolfgang Meyer, Wouter Swierstra. 1 comment

我们要感谢下面这些人,他们中很多人发表了许多的评论。

Aaron Hall, Abhishek Dasgupta, Adam Copp, Adam Langley, Adam Warrington, Adam Winiecki, Aditya Mahajan, Adolfo Builes, Al Hoang, Alan Hawkins, Albert Brown, Alec Berryman, Alejandro Dubrovsky, Alex Hirzel, Alex Rudnick, Alex Young, Alexander Battisti, Alexander Macdonald, Alexander Strange, Alf Richter, Alistair Bayley, Allan Clark, Allan Erskine, Allen Gooch, Andre Nathan, Andreas Bernstein, Andreas Schropp, Andrei Formiga, Andrew Butterfield, Andrew Calleja, Andrew Rimes, Andrew The, Andy Carson, Andy Payne, Angelos Sphyris, Ankur Sethi, António Pedro Cunha, Anthony Moralez, Antoine Hersen, Antoine Latter, Antoine S., Antonio Cangiano, Antonio Piccolboni, Antonios Antoniadis, Antonis Antoniadis, Aristotle Pagaltzis, Arjen van Schie, Artyom Shalkhakov, Ash Logan, Austin Seipp, Avik Das, Avinash Meetoo, BVK Chaitanya, Babu Srinivasan, Barry Gaunt, Bas van Dijk, Ben Burdette, Ben Ellis, Ben Moseley, Ben Sinclair, Benedikt Huber, Benjamin Terry, Benoit Jauvin-Girard, Bernie Pope, Björn Edström, Bob Holness, Bobby Moretti, Boyd Adamson, Brad Ediger, Bradley Unterrheiner, Brendan J. Overdiep, Brendan Macmillan, Brett Morgan, Brian Bloniarz, Brian Lewis, Brian Palmer, Brice Lin, C Russell, Cale Gibbard, Carlos Aya, Chad Scherrer, Chaddaï Fouché, Chance Coble, Charles Krohn, Charlie Paucard, Chen Yufei, Cheng Wei, Chip Grandits, Chris Ball, Chris Brew, Chris Czub, Chris Gallagher, Chris Jenkins, Chris Kuklewicz, Chris Wright, Christian Lasarczyk, Christian Vest Hansen, Christophe Poucet, Chung-chieh Shan, Conal Elliott, Conor McBride, Conrad Parker, Cosmo Kastemaa, Creighton Hogg, Crutcher Dunnavant, Curtis Warren, D Hardman, Dafydd Harries, Dale Jordan, Dan Doel, Dan Dyer, Dan Grover, Dan Orias, Dan Schmidt, Dan Zwell, Daniel Chicayban Bastos, Daniel Karch, Daniel Lyons, Daniel Patterson, Daniel Wagner, Daniil Elovkov, Danny Yoo, Darren Mutz, Darrin Thompson, Dave Bayer, Dave Hinton, Dave Leimbach, Dave Peterson, Dave Ward, David Altenburg, David B. Wildgoose, David Carter, David Einstein, David Ellis, David Fox, David Frey, David Goodlad, David Mathers, David McBride, David Sabel, Dean Pucsek, Denis Bueno, Denis Volk, Devin Mullins, Diego Moya, Dino Morelli, Dirk Markert, Dmitry Astapov, Dougal Stanton, Dr Bean, Drew Smathers, Duane Johnson, Durward McDonell, E. Jones, Edwin DeNicholas, Emre Sevinc, Eric Aguiar, Eric Frey, Eric Kidd, Eric Kow, Eric Schwartz, Erik Hesselink, Erling Alf, Eruc Frey, Eugene Grigoriev, Eugene Kirpichov, Evan Farrer, Evan Klitzke, Evan Martin, Fawzi Mohamed, Filippo Tampieri, Florent Becker, Frank Berthold, Fred Rotbart, Frederick Ross, Friedrich Dominicus, Gal Amram, Ganesh Sittampalam, Gen Zhang, Geoffrey King, George Bunyan, George Rogers, German Vidal, Gilson Silveira, Gleb Alexeyev, Glenn Ehrlich, Graham Fawcett, Graham Lowe, Greg Bacon, Greg Chrystall, Greg Steuck, Grzegorz Chrupała, Guillaume Marceau, Haggai Eran, Harald Armin Massa, Henning Hasemann, Henry Laxen, Hitesh Jasani, Howard B. Golden, Ilmari Vacklin, Imam Tashdid ul Alam, Ivan Lazar Miljenovic, Ivan Miljenovic, J. Pablo Fernández, J.A. Zaratiegui, Jaap Weel, Jacques Richer, Jake McArthur, Jake Poznanski, Jakub Kotowski, Jakub Labath, James Cunningham, James Smith, Jamie Brandon, Jan Sabbe, Jared Roberts, Jason Dusek, Jason F, Jason Kikel, Jason Mobarak, Jason Morton, Jason Rogers, Jeff Balogh, Jeff Caldwell, Jeff Petkau, Jeffrey Bolden, Jeremy Crosbie, Jeremy Fitzhardinge, Jeremy O'Donoghue, Jeroen Pulles, Jim Apple, Jim Crayne, Jim Snow, Joan Jiménez, Joe Fredette, Joe Healy, Joel Lathrop, Joeri Samson, Johannes Laire, John Cowan, John Doe, John Hamilton, John Hornbeck, John Lien, John Stracke, Jonathan Guitton, Joseph Bruce, Joseph H. Buehler, Josh Goldfoot, Josh Lee, Josh Stone, Judah Jacobson, Justin George, Justin Goguen, Kamal Al-Marhubi, Kamil Dworakowski, Keegan Carruthers-Smith, Keith Fahlgren, Keith Willoughby, Ken Allen, Ken Shirriff, Kent Hunter, Kevin Hely, Kevin Scaldeferri, Kingdon Barrett, Kristjan Kannike, Kurt Jung, Lanny Ripple, Laurențiu Nicola, Laurie Cheers, Lennart Kolmodin, Liam Groener, Lin Sun, Lionel Barret de Nazaris, Loup Vaillant, Luke Plant, Lutz Donnerhacke, Maarten Hazewinkel, Malcolm Reynolds, Marco Piccioni, Mark Hahnenberg, Mark Woodward, Marko Tosic, Markus Schnell, Martijn van Egdom, Martin Bayer, Martin DeMello, Martin Dybdal, Martin Geisler, Martin Grabmueller, Matúš Tejiščák, Mathew Manela, Matt Brandt, Matt Russell, Matt Trinneer, Matti Niemenmaa, Matti Nykänen, Max Cantor, Maxime Henrion, Michael Albert, Michael Brauwerman, Michael Campbell, Michael Chermside, Michael Cook, Michael Dougherty, Michael Feathers, Michael Grinder, Michael Kagalenko, Michael Kaplan, Michael Orlitzky, Michael Smith, Michael Stone, Michael Walter, Michel Salim, Mikael Vejdemo Johansson, Mike Coleman, Mike Depot, Mike Tremoulet, Mike Vanier, Mirko Rahn, Miron Brezuleanu, Morten Andersen, Nathan Bronson, Nathan Stien, Naveen Nathan, Neil Bartlett, Neil Whitaker, Nick Gibson, Nick Messenger, Nick Okasinski, Nicola Paolucci, Nicolas Frisby, Niels Aan de Brugh, Niels Holmgaard Andersen, Nima Negahban, Olaf Leidinger, Oleg Anashkin, Oleg Dopertchouk, Oleg Taykalo, Oliver Charles, Olivier Boudry, Omar Antolín Camarena, Parnell Flynn, Patrick Carlisle, Paul Brown, Paul Delhanty, Paul Johnson, Paul Lotti, Paul Moore, Paul Stanley, Paulo Tanimoto, Per Vognsen, Pete Kazmier, Peter Aarestad, Peter Ipacs, Peter Kovaliov, Peter Merel, Peter Seibel, Peter Sumskas, Phil Armstrong, Philip Armstrong, Philip Craig, Philip Neustrom, Philip Turnbull, Piers Harding, Piet Delport, Pragya Agarwal, Raúl Gutiérrez, Rafael Alemida, Rajesh Krishnan, Ralph Glass, Rauli Ruohonen, Ravi Nanavati, Raymond Pasco, Reid Barton, Reto Kramer, Reza Ziaei, Rhys Ulerich, Ricardo Herrmann, Richard Harris, Richard Warburton, Rick van Hattem, Rob Grainger, Robbie Kop, Rogan Creswick, Roman Gonzalez, Rory Winston, Ruediger Hanke, Rusty Mellinger, Ryan Grant, Ryan Ingram, Ryan Janzen, Ryan Kaulakis, Ryan Stutsman, Ryan T. Mulligan, S Pai, Sam Lee, Sandy Nicholson, Scott Brickner, Scott Rankin, Scott Ribe, Sean Cross, Sean Leather, Sergei Trofimovich, Sergio Urinovsky, Seth Gordon, Seth Tisue, Shawn Boyette, Simon Brenner, Simon Farnsworth, Simon Marlow, Simon Meier, Simon Morgan, Sriram Srinivasan, Sriram Srinivasan, Stefan Aeschbacher, Stefan Muenzel, Stephan Friedrichs, Stephan Nies, Stephan-A. Posselt, Stephyn Butcher, Steven Ashley, Stuart Dootson, Terry Michaels, Thomas Cellerier, Thomas Fuhrmann, Thomas Hunger, Thomas M. DuBuisson, Thomas Moertel, Thomas Schilling, Thorsten Seitz, Tibor Simic, Tilo Wiklund, Tim Clark, Tim Eves, Tim Massingham, Tim Rakowski, Tim Wiess, Timo B. Hübel, Timothy Fitz, Tom Moertel, Tomáš Janoušek, Tony Colston, Travis B. Hartwell, Tristan Allwood, Tristan Seligmann, Tristram Brelstaff, Vesa Kaihlavirta, Victor Nazarov, Ville Aine, Vincent Foley, Vipul Ved Prakash, Vlad Skvortsov, Vojtěch Fried, Wei Cheng, Wei Hu, Will Barrett, Will Farr, Will Leinweber, Will Robertson, Will Thompson, Wirt Wolff, Wolfgang Jeltsch, Yuval Kogman, Zach Kozatek, Zachary Smestad, Zohar Kelrich. 3 comments

最后,我们要感谢提交了超过800个评论的匿名读者们。

你可能感兴趣的:(Haskell,编程,正则表达式,软件测试,BREW)