什么是 Erlang?
Erlang 由 Ericsson 开发,用于帮助开发管理许多电信项目的软件。Erlang 的第一个版本发布于 1986 年,1998 年发布了它的第一个开放源码版本。可以从扩展的 Erlang 版本信息中了解到,Open Telecom Platform (OTP) 是适用于 Erlang 的应用程序开发平台,也是交付 Erlang 开发环境的主要方法。
Erlang 提供许多在其他语言中不存在或难以管理的标准特性。Erlang 中之所以存在这些功能,是因为它最初用于电信领域。
例如,Erlang 包含一个非常简单的并发模型,允许在同一主机上相对轻松地多次执行代码块。除了并发之外,Erlang 还使用一个错误模型,允许识别和处理这些进程中的错误(甚至可以用新进程处理),因此可以非常轻松地构建容错能力很强的应用程序。最后,Erlang 包含内置的分布式处理,允许在一台计算机上运行组件的同时从另一台计算机请求它们。
总之,Erlang 为构建分布式、可伸缩和高性能的离散应用程序提供了良好的环境,我们常常使用这种应用程序支持现代网络和基于 web 的应用程序。
函数编程与其他范例
Erlang 与其他流行的语言之间的主要差异是,Erlang 基本上是一种函数编程语言。函数编程与语言是否支持函数无关,而是指程序操作和组件的工作方式。
在函数编程中,按照与数学计算相似的方式设计语言的函数和操作,语言通过函数执行操作,函数接收输入并生成结果。函数编程范例 (paradigm) 意味着对于相同的输入值,代码块会产生相同的输出值。因此,预测函数或程序的输出容易得多,更容易调试和分析。
与之相对的编程范例是命令式编程语言,比如 Perl 或 Java,这类语言依赖于在执行期间应用程序状态的改变。在命令式编程语言中,状态的改变意味着:对于相同的输入值,程序的组件可以根据程序当时的状态而产生不同的结果。
函数编程方式很容易理解,但是如果您习惯了过程式和关注状态的命令式语言,可能不太容易适应它。
获得 Erlang
可以从 Erlang 网站直接获得 Erlang(参见 参考资料
)。许多 Linux 发行版的存储库中也包含它。例如,要想在 Gentoo 上安装它,可以使用 $ emerge dev-lang/erlang
。还可以使用 $ apt-get install erlang
在 Ubuntu 或 Debian 发行版上安装 Erlang。
对于其他 UNIX® 和 Linux 平台,可以下载源代码并手工构建它。从源代码构建 Erlang 需要 C 编译器和 make 工具(参见 参考资料
)。基本步骤如下:
- 解压源代码:
$ tar zxf otp_src_R14B01.tar.gz
- 切换目录:
$ cd otp_src_R14B
- 运行配置脚本:
$ ./configure
- 运行 make 以构建代码:
$ make
还可以从 Erlang 网站获得 Windows® 安装程序(参见 参考资料
)。
第一个 Erlang 程序,一个递归的 Fibonacci 函数
要想了解函数编程风格的好处以及它在 Erlang 中的实现方式,最好的方法是了解 Fibonacci 函数。Fibonacci 数列是一种整数序列,可以使用以下算式计算各个 Fibonacci 值:F(n) = F(n-1) + F(n-2)
。
第一个值 F(0)
的结果是 0
,F(1)
的结果是 1
。在此之后,通过把前两个值相加求出 F(n)
。例如,F(2)
的计算过程见 清单 1
。
清单 1. F(2)
的计算过程
F(2) = F(2-1) + F(2-2)
F(2) = F(1) + F(0)
F(2) = 1 + 0
F(2) = 1
|
Fibonacci 数列对于许多系统(包括分析金融数据)都很重要,它还是在树结构的主干和分支上安排叶节点的基础。如果您玩过使用 3D 树的视频游戏,就会知道,这类游戏很可能使用 Fibonacci 数列来确定分支和叶的位置。
在用编程语言编写 Fibonacci 计算时,可以使用递归来实现,即函数通过调用本身从 root(F(0)
和 F(1)
)开始计算数字。
在 Erlang 中,可以用变量和固定的值创建函数。这样可以简化 Fibonacci 数列的计算,因为 F(0)
和 F(1)
返回的是固定的值,而不是计算出的值。
因此,基本函数有三种情况:提供的值是 0
、1
和任何更高的值。在 Erlang 中,使用分号分隔语句,所以可以用 清单 2
所示的代码定义基本 Fibonacci 函数。
清单 2. 基本 Fibonacci 函数
fibo(0) -> 0 ;
fibo(1) -> 1 ;
fibo(N) when N > 0 -> fibo(N-1) + fibo(N-2) .
|
第一行定义调用 fibo(0)
的结果(->
把定义与函数体分隔开),第二行定义调用 fibo(1)
的结果,第三行定义在提供正值 N
时执行的计算。可以这样做是因为在 Erlang 中有一个称为模式匹配的系统,后面会详细讨论这个系统。注意,最后一个语句(和 Erlang 中的所有语句)以句号结尾。实际的计算非常简单。
现在,我们来仔细查看一下 Erlang 语言的结构。
基础知识
如果您习惯了 Perl、Python 或 PHP 等语言,那么 Erlang 的结构和布局看起来可能有点儿怪,但它的某些方面会极大地简化应用程序的编写过程,让您不必为代码的许多方面操心。尤其是,Erlang 代码比其他语言少得多,某些操作、表达式和构造往往只有一行。
了解 Erlang 最简便的方法是使用 Erlang shell。安装 Erlang 之后,可以通过在命令行上执行 erl
运行 Erlang shell,参见 清单 3
。
清单 3. 使用 Erlang shell
$ erl
Erlang R13B04 (erts-5.7.5) [source] [rq:1] [async-threads:0]
Eshell V5.7.5 (abort with ^G)
1>
|
可以在提示符下输入语句(语句应该以句号结尾)。shell 会执行语句。因此,输入一个简单的求和语句会返回 清单 4
所示的结果。
清单 4. 输入简单的求和语句
下面使用 shell 研究一些数据类型和构造。
数据类型
Erlang 支持基本数据类型(比如整数和浮点数)和更复杂的结构(比如元组和列表)。
整数和大多数整数操作与其他语言相同。可以把两个数字相加,参见 清单 5
。
清单 5. 将两个数字相加
可以使用圆括号组织算式,参见 清单 6
。
清单 6. 使用圆括号组织算式
注意,在清单 6 中结束语句的句号在另一行上,输入句号之后方可执行前面的计算。
在 Erlang 中,会使用浮点数代表实数,并且可以自然地表达浮点数,参见 清单 7
。
清单 7. 自然地表示浮点数
还可以使用指数表示浮点数,参见 清单 8
。
清单 8. 使用指数表示浮点数
4> 10.9E-2 +4.5
4> .
4.609
|
在整数和浮点数上,都支持使用标准的数学操作符(+、-、/ 和 *),可以在算式中混合使用浮点数和整数。但是,如果对浮点数使用取模和求余数操作符,则会产生错误,因为这些操作符只支持整数。
原子值
原子值是静态的(即不变的)字面值。清单 9
给出一个示例。
清单 9. 原子值
8> abc.
abc
9> 'Quoted literal'.
'Quoted literal'
|
原子值的使用方式应该与 C 中的 #define
相同,也就是说,作为一种明确指定或标识值的方法。因此,对于原子值,惟一合法的操作是比较。还可以将原子值的这种使用方法扩展到布尔逻辑,利用原子值 true 和 false 来标识语句的布尔结果。原子值必须以小写字母开头,否则需要加上单引号。
例如,可以比较整数并获得布尔原子值结果,参见 清单 10
。
清单 10. 比较整数以获得布尔原子值
还可以比较原子值,参见 清单 11
。
清单 11. 比较原子值
原子值本身按字母表次序排序(即 z
的值大于 a
),参见 清单 12
。
清单 12. 原子值按字母表次序排序
可以使用标准的布尔操作符,比如 and
、or
、xor
和 not
。还可以使用 is_boolean()
函数检查提供的值是 true 还是 false。
元组
元组是复合的数据类型,用于存储数据项的集合。元组要放在花括号中(参见 清单 13
)。
清单 13. 元组
14> {abc, def, {0, 1}, ghi}.
{abc,def,{0,1},ghi}
|
一个元组的内容不必都是相同类型的。元组的构造很特殊,其中的第一个值为原子值。在这种情况下,第一个原子值称为标签,可以使用它来标识内容或对内容进行分类(参见 清单 14
)。
清单 14. 第一个值为原子值的元组
16> { email, 'example@example.org'}.
{email,'example@example.org'}
|
在这里标签是 email,可以使用标签标识此元组中其余的内容。
元组对于包含定义的元素和描述各种复杂数据结构非常有用。Erlang 允许显式地设置和获取元组中的值(参见 清单 15
)。
清单 15. 显式地设置和获取元组中的值
17> element(3,{abc,def,ghi,jkl}).
ghi
18> setelement(3,{abc,def,ghi,jkl},mno).
{abc,def,mno,jkl}
|
注意,元组元素以 1
作为第一个值的索引,而不是像其他大多数语言中那样从 0 开始。还可以将元祖作为整体进行比较(参见 清单 16
)。
清单 16. 作为整体比较元组
19> {abc,def} == {abc,def}.
true
20> {abc,def} == {abc,mno}.
false
|
列表
最后一个数据类型是列表,列表用方括号表示。列表与元组相似,但是元组只能在比较中使用,而列表允许执行的操作更多。
基本的列表如 清单 17
所示。
清单 17. 基本的列表
22> [1,2,3,abc,def,ghi,[4,56,789]].
[1,2,3,abc,def,ghi,[4,56,789]]
|
字符串实际上是特殊类型的列表。Erlang 不直接支持字符串的概念,但是可以使用带双引号的值创建字符串值(参见 清单 18
)。
清单 18. 使用带双引号的值创建字符串值
但是,字符串实际上只是由 ASCII 字符值组成的列表。因此,上面的字符串存储为由 ASCII 字符值组成的列表(参见 清单 19
)。
清单 19. 字符串存储为由 ASCII 字符值组成的列表
24> [72,101,108,108,111].
"Hello"
|
还可以使用 $Character
表示法指定字符(参见 清单 20
)。
清单 20. 使用 $Character
表示法指定字符
25> [$H,$e,$l,$l,$o].
"Hello"
|
列表(包括字符串,即字符的列表)支持许多操作。这是字符串与原子值之间的主要区别。原子值是静态的标识符,但是可以通过操作字符串的组成部分(各个字符)来操作字符串。例如,不能标识原子值(比如 'Quick brown fox'
)中的各个单词,因为原子值是单一实体。但是,您可以把字符串分割为单词:["Quick","brown","fox"]
。
lists 模块中提供了许多用于操作列表的函数。例如,可以使用 sort 函数对列表中的数据项进行排序。因为这些是内置的函数,所以必须指定模块和函数名(参见 清单 21
)。
清单 21. 指定模块和函数名
34> lists:sort([4,5,3,2,6,1]).
[1,2,3,4,5,6]
|
列表操作
可以使用构造函数构造包含多个元素的列表,它用一个元素和另一个列表构造列表。在其他语言中,这种构造操作由用于 push()
的函数或操作符处理。在 Erlang 中,使用 |
(管道)操作符分隔头(列表的开头)和尾,表达方式为 [Head|Tail]
。头是单一元素,尾是列表的其余部分。
清单 22
展示了如何在列表的开头添加新的值。
清单 22. 在列表的开头添加新的值
可以重复执行这种操作以构造整个列表,参见 清单 23
。
清单 23. 重复执行这种操作以构造整个列表
31> [1|[2|[3|[]]]].
[1,2,3]
|
在这个示例中,末尾的空列表意味着您构造了一个结构良好(合适)的列表。注意,第一项必须是一个元素,不能是列表片段。如果以其他方式执行合并,则会构造一个嵌套式列表(参见 清单 24
)。
清单 24. 构造嵌套的列表
30> [[1,2]|[2,3]].
[[1,2],2,3]
|
最后,可以使用 ++
操作符合并列表,参见 清单 25
。
清单 25. 使用 ++
操作符合并列表
35> [1,2] ++ [3,4].
[1,2,3,4]
|
还可以从操作符左边的列表中删除右边列表中的所有元素(参见 清单 26
)。
清单 26. 删除列表中的元素
36> [1,2,3,4] -- [2,4].
[1,3]
|
因为字符串是列表,所以这些操作也适用于字符串(参见 清单 27
)。
清单 27. 这些操作也适用于字符串
37> "hello" ++ "world".
"helloworld"
40> ("hello" -- "ello") ++ "i".
"hi"
|
尽管这里只简要介绍了数据类型,但是我们希望让您对基本数据类型和操作有足够的了解。
表达式和模式匹配
在研究数据类型时,我们已经看到了许多表达式和构造。表达式的重要元素是变量。Erlang 中的变量必须以大写字母开头,后面是大写字母、小写字母和下划线的任意组合(参见 清单 28
)。
清单 28. Erlang 中的变量
在 Erlang 中,在对变量赋值时,是一次性将值绑定到变量。绑定变量之后,就不能改变它的值(参见 清单 29
)。
清单 29. 将值绑定到变量
42> Value = 100.
** exception error: no match of right hand side value 100
|
这与大多数语言不一样 — 变量的定义通常意味着值是可变的。在 Erlang 中,只能赋值一次意味着:如果希望向计算某个值的结果,则必须将它赋值给新的变量(参见 清单 30
)。
清单 30. Erlang 中变量的限制
43> Sum = Value + 100
199
|
只能赋值一次的好处是,在计算过程中很难意外地设置或改变变量值,这让值的识别和调试变得更容易,也让代码更为清晰,有时候更简短(因为可以简化结构)。
注意,这种操作意味着先计算出值,然后把值绑定到变量。在其他语言中,可以根据函数或操作的引用设置值,这意味着值取决于访问它时引用的值。在 Erlang 中,在创建变量时它的值总是已知的。
可以使用 f(Varname)
显式地忽略一个变量的绑定,或使用 f()
忽略所有变量的绑定。
为变量赋值实际上就是一种特殊的模式匹配。Erlang 中的模式匹配还会处理各个语句的执行流,以及从复合数据类型(元组、数组)中提取出值。模式匹配的基本形式是:模式 = 表达式。
表达式由数据结构、绑定的变量(即具有值的变量)、数学操作符和函数调用组成。操作的两边必须匹配(也就是说,如果模式是包含两个元素的元组,那么表达式的计算结果也必须是包含两个元素的元组)。在执行表达式时,计算表达式并将结果赋值给模式。
例如,可以使用一个模式匹配同时为两个变量赋值(参见 清单 31
)。
清单 31. 同时给两个变量赋值
48> {A,B} = {(9+45),abc}.
{54,abc}
|
注意,如果模式是绑定的变量,或者模式的元素是绑定的变量,那么模式匹配的结果就会变成比较。此操作支持实现强大的选择性赋值。例如,为了从元组中获取姓名和电子邮件地址,可以使用以下模式匹配:{contact, Name, Email} = {contact, "Me", "me@example.com"}
。
最后,可以按前面提到的构造表示方法,使用模式匹配从列表或元组中提取元素。例如,清单 32
展示了如何获得列表中的前两个元素,同时保留其余元素。
清单 32. 获得列表中的前两个元素,同时保留其余元素
53> [A,B|C] = [1,2,3,4,5,6].
[1,2,3,4,5,6]
|
A
赋值为 1
,B
赋值为 2
,C
赋值为列表的其余部分。
函数
与其他语言一样,Erlang 中的函数是所有程序的基本组成部分。函数由函数名(由一个原子值定义)和圆括号中的零个或更多函数参数组成:sum(N,M) -> N+M
。
函数必须在文件中的模块中定义(不能在 shell 中定义函数)。参数可以包含复合数据类型。例如,可以使用元组中的标签选择不同的操作(参见 清单 33
)。
清单 33. 可以使用元组中的标签选择不同的操作
mathexp({sum, N,M}) -> N+M ;
mathexp({sub, N,M}) -> N-M ;
mathexp({square, N}) -> N*N.
|
分号是每个函数定义之间的 “或” 操作符。使用模式匹配评估函数的参数,所以如果把包含三个元素的元组提供给 mathexp()
函数,模式匹配会失败。
Erlang 中的函数还可以接受不同数量的参数。Erlang 会执行模式匹配,直到找到有效的函数定义,从而选择适当的函数定义。函数的参数数量称为元数 (arity),用于帮助标识函数。
再看一下 Fibonacci 示例,现在您就会发现,当调用 fibo(0)
时,模式与函数的第一个定义匹配,fibo(1)
与第二个定义匹配,其他值与最后一个定义匹配。这也解释了函数执行的递归是如何实现的。例如,在调用 fibo(9)
时,可以使用相应的值调用 fibo(N)
函数定义,直到到达 fibo(0)
和 fibo(1)
函数定义(它们返回固定的值)。
任何函数的返回值都是子句(在我们的示例中只有一行)中最后一个表达式的结果。注意,只有在找到了匹配项且变量是函数局部变量的情况下,才会为变量赋值。
模块
与其他语言中的模块一样,模块用于把相似的函数集中在一起。
在文件中指定模块名(必须与文件名匹配),然后指定模块中希望导出到装载此模块的其他程序的函数。例如,清单 34
给出了文件 fib.erl,其中包含 fib 模块的定义。
清单 34. fib.erl 文件
-module(fib).
-export([fibo/1, printfibo/1]).
%% print fibo arg. and result, with function as parameter
printfibo(N) ->
Res = fib:fibo(N),
io:fwrite("~w ~w~n", [N, Res]).
fibo(0) -> 0 ;
fibo(1) -> 1 ;
fibo(N) when N > 0 -> fibo(N-1) + fibo(N-2) .
|
模块声明位于 -module()
行中。-export()
行包含要导出的函数的列表。每个函数的定义都给出了函数名和函数的元数,以便您能导出函数的特定定义。
要使用模块,则需要编译并装载模块。可以在 shell 中使用 c()
语句完成这个步骤,参见 清单 35
。
清单 35. 使用 c()
语句编译并装载模块
1> c(fib).
{ok,fib}
2> fib:printfibo(9).
9 34
ok
|
注意,函数调用包含模块名,从而确保调用的是 fib 模块中的 printfibo()
函数。
结束语
Erlang 的结构和格式与大多数其他语言有很大区别。尽管许多数据类型和基本的表达式是相同的,但是它们的用法和应用不太一样。变量只能赋值一次,通过模式匹配系统对不同的表达式进行运算,这些特性给典型的语言环境提供了一些强大的扩展。例如,可以为同一函数定义多种处理方式,还可以对递归调用应用模式匹配,这样做可以简化某些函数。
在下一篇文章中,我们将讨论 Erlang 的进程、消息解析和网络功能,并通过研究 MochiWeb HTTP 服务器了解这种语言的强大功能和灵活性。
本文转载于developerWorks,原文在这里
分享到:
相关推荐
《erlang/otp并发编程实战》主要分为三大部分:第一部分讲解erlang 编程及otp 基础;第二部分讲解如何在实际开发中逐一添加otp 高级特性,从而完善应用,作者通过贯穿本书的主项目——加速web 访问的分布式缓存...
erlang OTP并发编程实战,连城译著,清晰版的,学习erlang的必看书籍。 (积分权限不够,只能分两部分了)
erlang OTP并发编程实战,连城译著,清晰版的,学习erlang的必看书籍。 第二部分(积分权限不够,只能分两部分了)
小部分。比如,我将只会告诉你最简单的语法,而不是所有详细的结构原理。有很多极其简 单的东西我会写上*manual*,这就表示这里有很多信息,你可以在Erlang相关的书中找 到或是在<Erlang参考手册>中找得到。 我也...
Erlang 是一种多用途编程语言,主要用于开发并发和分布式系统。它最初是一种专有的编程语言,Ericsson 使 用它来开发电话和通信应用程序。 本教程目的是告诉你如何快速高效地学习 Erlang 语言。教程中只讲述了 ...
第二部分:异步编程初探与reactor模式 第三部分:初步认识Twisted 第四部分:由Twisted支持的诗歌客户端 第一个twisted支持的诗歌服务器 第一滴心血 第五部分:由Twisted支持的诗歌客户端 第一滴心血 第六...
2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11 2.12 2.13 2.14 3.1 3.2 3.3 3.4 4.1 4.2 4.3 和Erlang互操作 错误处理 可执⾏⽂件 并发OTP并发 OTP Supervisors OTP 分布式 元编程 Umbrella Projects ...
它针对低延迟和低内存使用进行了优化,部分原因是Cowboy Cowboy是适用于Erlang / OTP的小型,快速,现代的HTTP服务器。 Goals Cowboy的目标是在一个小的代码库中提供完整的HTTP堆栈。 它针对低延迟和低内存使用进行...
Erlang是一种编程语言,用于构建对高可用性有要求的大规模可扩展软实时系统。 它的一些用途是在电信,银行,电子商务,计算机电话和即时消息中。 Erlang的运行时系统具有对并发,分发和容错的内置支持。 它是任何...
第1章 Erlang教程 串行编程 数据类型 模式识别 内置函数 并发 第2章串行编程 项式 模式匹配 表达式求值 模块系统 函数定义 原语 算术表达式 变量作用域 第3章列表编程 用于列表处理的BIF 常用列表...
二郎任务Erlang Quest 是一个小游戏,您可以在其中解决 Erlang 编程任务,从非常简单的东西开始。 Erlang Quest 是一种练习 Erlang 的方式——在 Erlang 中写作和解决问题。 它不包括 Erlang 语法等方面的教程——...
通用语言GML 是用 Erlang 编程语言编写的康威生命游戏。 它在无边无际的空间中运行,所以要小心——它会吃掉你的宇宙。 作者:米哈伊尔·库尔科夫用法克隆存储库后运行简单的make命令 - 它将启动 Erlang shell 并...
塞兰·伍珀 该存储库对应于的一部分,该部分收集了所有WOOPER相关的元素,用于使用Erlang进行面向对象的编程。 请参阅,否则请参阅其。 “主”分支旨在对应于该层的当前稳定版本。
当使用非Erlang编程语言进行软件扩展时,或在将软件系统(全部或部分)转换为Erlang编程语言期间,CloudI可以减轻软件开发风险(延迟或故障)。应该如何使用CloudI? CloudI API以任何受支持的语言(当前为C / C ++...
编程语言中的快速反平方根 这是我用多种语言编写快速反平方根算法所面临的挑战的资源库。 用多种语言编写一种算法很有趣。 我用从未有过的语言写过一些代码。 我了解了语言之间的差异和相似之处,以及其他语言如何...
最初使用的编程语言是Erlang,但现在我们转向Elixir。讲课将有14堂讲座将讲解功能和并发编程的概念。 我们将使用Elixir作为示例语言,但讲座更侧重于全局。 学习Elixir是您在编程时最好学习的东西。练习题强烈建议...
RabbitMQ服务器使用Erlang编程语言编写,并基于Open Telecom Platform框架构建,用于集群和故障转移。 与代理接口的客户端库适用于所有主要编程语言。 TL; DR $ docker run --name rabbitmq bitnami/rabbitmq:...
写在例如Go 或 Erlang 旨在处理并行编程范式。 另一方面,Erlang 不太擅长处理字符串,您可能需要用 Java 为用户界面编写一个小型前端。 (此实验不固定在 Kattis 上。) 背景 下载示例代码。 服务器部分有两个类 ...
【第一部分】 (豆瓣阅读,免费书籍) 其它 Android Google Material Design 正体中文版( ) Android 一些重要知识点解析整理 APP AWK C/C++ (欢迎大家参与在线翻译和校对) (宋劲杉, 北京亚嵌教育研究中心) (中英文版) ...