简介

关于本教程

这是“学习 Erlang 为你带来好处!”的开篇。阅读本教程应该是你学习 Erlang 的第一步,所以让我们来谈谈它。

Erlang logo

首先,我在阅读了 Miran Lipovača 的 学习 Haskell 为你带来好处!(LYAH) 教程后,开始萌生了写这本书的想法;我认为他做得很好,让这门语言变得有吸引力,学习体验也变得友好。由于我之前就认识他,我问他他对我的 Erlang 版本的书有什么看法。他喜欢这个想法,对 Erlang 有点兴趣。

所以我现在在这里打字。当然,我的动力还有其他来源:我主要发现进入这门语言很困难(网上文档稀少,否则你需要买书),我认为社区会受益于一本类似 LYAH 的指南。更重要的是,我看到有些人对 Erlang 夸大或贬低,有时基于笼统的概括。然后有些人坚信 Erlang 不过是一种炒作。如果我想说服他们,我知道他们不太可能从一开始就读这本书。

因此,这本书希望成为一种学习 Erlang 的方式,适合那些具备命令式语言(如 C/C++、Java、Python、Ruby 等)基本编程知识的人,他们可能知道也可能不知道函数式编程(Haskell、Scala、Erlang、Clojure、OCaml...)。我也想以诚实的方式写这本书,展示 Erlang 的本来面目,承认它的缺点和优点。

那么什么是 Erlang 呢?

首先,Erlang 是一种函数式编程语言。如果你曾经使用过命令式语言,像 i++ 这样的语句可能对你来说很正常;在函数式编程中,它们是不允许的。事实上,改变任何变量的值都是严格禁止的!这乍一看可能很奇怪,但如果你还记得你的数学课,这实际上是你学到的方式

y = 2
x = y + 3
x = 2 + 3
x = 5

如果我添加了以下内容

x = 5 + 1
x = x
∴ 5 = 6

你会感到非常困惑。函数式编程认识到这一点:如果我说 x 是 5,那么我不能逻辑上声称它也是 6!这将是不诚实的。这也是为什么具有相同参数的函数应该始终返回相同结果的原因

x = add_two_to(3) = 5
∴ x = 5

对于相同参数始终返回相同结果的函数称为引用透明。它使我们能够用 5 代替 add_two_to(3),因为 3+2 的结果将始终是 5。这意味着我们可以将数十个函数粘合在一起,以解决更复杂的问题,同时确保不会出现任何问题。逻辑清晰,不是吗?但是有一个问题

x = today() = 2009/10/22
  -- wait a day --
x = today() = 2009/10/23
x = x
∴ 2009/10/22 = 2009/10/23

哦,不!我美丽的方程式!它们突然都变得错误了!为什么我的函数每天返回不同的结果?

显然,在某些情况下,打破引用透明是有用的。Erlang 对函数式编程采取了这种非常务实的做法:遵守其最纯粹的原则(引用透明、避免可变数据等),但当现实世界的问题出现时,就从这些原则中脱离出来。

An envelope

现在,我们将 Erlang 定义为一种函数式编程语言,但它也非常强调并发和高可靠性。为了能够同时执行数十个任务,Erlang 使用了 actor 模型,每个 actor 都是虚拟机中的一个独立进程。简而言之,如果你是在 Erlang 世界中的一个 actor,你将是一个孤独的人,坐在一个没有窗户的黑暗房间里,等待你的邮箱收到消息。一旦你收到消息,你就会以特定方式做出反应:收到账单后你就支付账单,收到生日贺卡后你就回复一封“谢谢”信,你也会忽略你不理解的信件。

可以将 Erlang 的 actor 模型想象成一个世界,每个人都独自坐在自己的房间里,可以执行一些不同的任务。每个人都严格通过写信来交流,仅此而已。虽然这听起来像是一种无聊的生活(以及邮政服务的新时代),但这意味着你可以让许多人为你执行非常具体的任务,他们永远不会做错事或犯错误,而这些错误会对其他人的工作产生影响;他们甚至可能不知道除你之外其他人的存在(这很好)。

为了摆脱这种类比,Erlang 强制你编写 actor(进程),除非它们互相传递消息,否则它们不会与其他代码片段共享任何信息。每种通信都是明确的、可追溯的,并且安全的。

当我们定义 Erlang 时,我们是站在语言的层面上,但从更广泛的意义上来说,这并不是全部:Erlang 也是一个完整的开发环境。代码被编译成字节码,并在虚拟机中运行。因此,Erlang,就像 Java 和患有多动症的孩子一样,可以在任何地方运行。标准发行版包括(除其他外)开发工具(编译器、调试器、分析器、测试框架)、Open Telecom Platform (OTP) 框架、Web 服务器、解析器生成器和 mnesia 数据库,这是一个键值存储系统,能够在多个服务器上自我复制,支持嵌套事务,并允许你存储任何类型的 Erlang 数据。

虚拟机和库还允许你在不中断任何程序的情况下更新正在运行的系统的代码,轻松地在多台计算机上分发你的代码,并以简单而强大的方式管理错误和故障。

A crashed plane

我们将在后面看到如何使用这些工具中的大多数并实现安全性,但现在,我会告诉你 Erlang 中的相关一般策略:让它崩溃。不是像一架载着数十名乘客的飞机坠毁,而是更像一个在下面有安全网的走钢丝的人。虽然你应该避免犯错,但在大多数情况下,你不需要检查每种类型或错误条件。

Erlang 从错误中恢复、使用 actor 组织代码,并使其通过分布式和并发扩展的能力听起来都非常棒,这引出了下一节...

不要喝太多酷乐时

在书中可能会有许多像这样的小黄橙色部分(你看到它们的时候就会认出来)。Erlang 目前正变得越来越受欢迎,因为它得到了热情的宣传,这可能导致人们认为它比实际情况更强大。这些提醒将帮助你保持冷静,如果你也是这些过度热情的学习者之一。

第一个例子与 Erlang 由于其轻量级进程而带来的巨大扩展能力有关。Erlang 进程确实是轻量级的:你可以同时拥有数十万个进程,但这并不意味着你必须以这种方式使用它,仅仅因为你可以。例如,创建一个射击游戏,其中包括子弹在内的所有东西都是自己的 actor,这简直是疯狂。你唯一能用这种游戏射击的就是自己的脚。从一个 actor 发送消息到另一个 actor 仍然需要一小部分成本,如果你将任务分解得太多,你会让事情变得更慢

当我们学习得足够深入,真正开始担心这个问题时,我会详细介绍它,但请记住,只是随机地在问题中添加并行处理并不能让它运行得更快。别伤心;在某些情况下,使用数百个进程既是可能的,也是有用的!只是它并非始终如此。

人们还说 Erlang 能够以与计算机核心数量成正比的方式进行扩展,但这通常不正确:糟糕的图表:速度与核心:它只是扩展了! 这可能是可能的,但大多数问题并不会以让你能够同时运行所有内容的方式表现。

还有一些需要记住的事情:虽然 Erlang 在某些方面做得很好,但在技术上仍然可以使用其他语言获得相同的结果。反之亦然;根据需要评估每个问题,并根据要解决的问题选择合适的工具。Erlang 不是银弹,它在图像和信号处理、操作系统设备驱动程序等方面表现特别差,但在服务器端的大型软件(例如:队列、MapReduce)、与其他语言相结合完成一些工作、更高级别的协议实现等方面表现出色。中间的领域将取决于你。你不应该仅仅使用 Erlang 来构建服务器软件:有一些人做了出乎意料和令人惊讶的事情。一个例子是 IANO,这是一个由 UNICT 团队创建的机器人,它使用 Erlang 来实现人工智能,并在 2009 年 eurobot 比赛 中获得了银牌。另一个例子是 Wings 3D,一个用 Erlang 编写的开源 3D 建模器(但不是渲染器),因此它也是跨平台的。

你需要深入学习什么

你只需要一个文本编辑器和 Erlang 环境即可开始。你可以在 官方 Erlang 网站 上获取源代码和 Windows 二进制文件。我不会详细介绍安装过程,但对于 Windows,只需下载并运行二进制文件即可。不要忘记将你的 Erlang 目录添加到 PATH 系统变量中,以便能够从命令行访问它。

在基于 Debian 的 Linux 发行版中,你应该能够通过执行 $ apt-get install erlang 来安装软件包。在 Fedora 上(如果你安装了 'yum'),你可以通过输入 # yum install erlang 来实现相同的效果。但是,这些存储库通常包含过时的 Erlang 软件包版本;使用过时的版本会导致你与本教程中得到的结果产生一些差异,并且某些应用程序的性能也会受到影响。因此,我建议你从源代码编译。查阅软件包中的 README 文件,并使用 Google 来获取所需的安装详细信息,它们比我做得要好得多。

在 FreeBSD 上,你有很多选择。如果你使用 portmaster,你可以执行 portmaster lang/erlang。对于标准端口,应该是 cd /usr/ports/lang/erlang; make install clean。最后,如果你想使用软件包,运行 pkg_add -rv erlang

如果你使用的是 OSX,你可以使用 $ brew install erlang(使用 Homebrew)或 $ port install erlang(如果你更喜欢 MacPorts)来安装 Erlang。

或者,Erlang Solutions Ltd. 提供了 适用于所有主要操作系统的软件包,这些软件包通常运行良好(选择“标准”发行版)。

注意:在撰写本文时,我使用的是 Erlang 版本 R13B+,但为了获得最佳效果,你应该使用更新的版本。

在哪里获得帮助

你可以从几个地方获得帮助。如果你使用的是 linux,你可以访问手册页以获取良好的技术文档。Erlang 有一个 lists 模块(我们很快就会看到):要获取有关 lists 的文档,只需输入 $ erl -man lists

在 Windows 上,安装应该包括 HTML 文档。你可以随时从 官方 Erlang 网站 上下载它,或者查看 更干净的替代网站 之一。

如果您需要整理代码,可以参考 这里 的良好编码实践。本书中的代码也将尝试遵循这些指南。

现在,有些时候仅仅了解技术细节是不够的。当这种情况发生时,我倾向于求助于两个主要来源:官方的 邮件列表(您应该关注它,仅仅是为了学习很多东西)和 #erlang 频道,位于 irc.freenode.net

哦,如果您是喜欢烹饪书和预制食谱的人,trapexit 就是您要找的地方。他们还镜像了邮件列表作为论坛和一个通用维基,这始终会有所帮助。