基础知识_基础

基础知识

什么是Erlang?

Erlang由爱立信开发,旨在帮助开发用于管理许多不同电信项目的软件,第一版于1986年发布,第一版开源于1998年。您可以在扩展的Erlang中看到这一点。在存在Erlang应用程序开发平台的开放电信平台(OTP)作为提供Erlang开发环境的主要方法的地方发布信息。

Erlang提供了许多其他语言无法找到或难以管理的标准功能。 由于Erlang是电信行业的根源,所以其中大部分功能都存在于Erlang中。

例如,Erlang包含一个非常简单的并发模型,允许相对容易地在同一主机上多次执行单个代码块。 除了这种并发性之外,Erlang还使用错误模型,即使通过新过程也可以识别和处理这些过程中的故障,这使得构建高度容错的应用程序非常容易。 最后,Erlang包含内置的分布式处理,使组件可以在一台机器上运行,而又可以从另一台机器上请求。

放在一起,Erlang提供了一个绝佳的环境来构建我们经常用来支持现代网络和基于Web的应用程序的分布式,可伸缩和高性能离散应用程序的类型。

函数式编程与其他范例

Erlang与更流行的语言之间的主要区别是Erlang主要是一种功能编程语言。 这与是否支持功能无关,但与程序和组件的操作方式有关。

通过函数式编程,语言的功能和操作以与数学计算类似的方式进行设计,因为语言对输入并产生结果的函数进行运算。 功能编程范例意味着代码的各个块可以为相同的输入值产生一致的输出值。 这使得预测函数或程序的输出变得容易得多,因此更易于调试和分析。

相反的编程范例是命令式编程语言,例如Perl或Java,它依赖于在执行过程中更改应用程序的状态。 命令式编程语言中状态的改变意味着,基于当时的程序状态,程序的各个组件可以使用相同的输入值产生不同的结果。

函数式编程方法易于理解,但如果习惯于过程性和以状态为中心的命令式语言,则可能很难应用。

获取Erlang

您可以直接从Erlang网站获得Erlang(请参阅参考资料 )。 许多Linux发行版也将其包含在其存储库中。 例如,要在Gentoo上安装,可以使用: $ emerge dev-lang/erlang 。 或者,您可以使用以下$ apt-get install erlang在Ubuntu或Debian发行版上安装Erlang: $ apt-get install erlang

对于其他UNIX®和Linux平台,您可以下载源代码并手动构建它。 您将需要C编译器和make工具来从源代码进行构建(请参阅参考资料 )。 基本步骤如下:

  1. 解压缩源代码: $ tar zxf otp_src_R14B01.tar.gz
  2. 转到目录: $ cd otp_src_R14B
  3. 运行配置脚本: $ ./configure
  4. 最后运行make构建: $ make

也可以从Erlang网站获得Windows®安装程序(请参阅参考资料 )。

您的第一个Erlang程序,递归斐波那契函数

要了解函数式编程风格的好处以及它在Erlang中的工作方式,一种完美的方法是查看Fibonacci函数。 斐波那契数是一个整数序列,对于给定数,斐波那契值可以使用以下公式计算: F(n) = F(n-1) + F(n-2)

第一个值F(0)的结果为0 ,而F(1)的结果为1 。 之后,您可以通过计算前两个值并将它们相加来确定F(n) 。 例如, 清单1显示了F(2)的计算。

清单1. F(2)计算
F(2) = F(2-1) + F(2-2)
F(2) = F(1) + F(0)
F(2) = 1 + 0
F(2) = 1

斐波那契数列是许多系统的重要计算和捷径,包括财务数据分析,并且是将树叶布置在树的茎或枝上的基础。 如果您使用3D树木玩电子游戏,则可能使用斐波那契数列计算树枝和树叶的位置,以确定树枝和树叶的位置。

使用编程语言对计算进行编程时,可以使用递归来实现计算,在递归中,函数会调用自身以便从根F(0)F(1)计算数字。

在Erlang中,您可以创建具有变量和固定值的函数。 这简化了斐波那契数列中的情况,其中F(0)F(1)返回显式值,而不是计算得出的值。

因此,基本功能具有三种情况,一种情况是提供0 ,另一种情况是1 ,以及其他任何更高的值。 在Erlang中,使用分号分隔这些语句,因此可以定义基本的Fibonacci函数,如清单2所示。

清单2.基本的斐波那契函数
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,您可以在安装Erland之后在命令行中运行erl来执行该外壳程序。 您可以在清单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.输入一个简单的总和
1> 3+4.
7

我们将使用shell查看一些不同的类型和构造。

号码类型

Erlang支持基本数据类型,例如整数,浮点数和更复杂的结构,例如元组和列表。

整数和大多数整数运算与其他语言相同。 您可以将两个数字加在一起,如清单5所示。

清单5.将两个数字加在一起
1> 3+4.
7

您可以使用括号将计算分组在一起,如清单6所示。

清单6.使用括号将计算分组
2> (4+5)*9
2> .
81

注意,在清单6中,终止语句段在单独的一行上,用于评估前面的计算。

Erlang中的浮点数用来表示实数,并且可以自然地表达,如清单7所示。

清单7.自然表达的浮点数
3> 4.5 + 6.2 . 
10.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.比较整数以获得布尔原子
10> 1 == 1.
true

或者,您可以比较原子,如清单11所示。

清单11.比较原子
11> abc == def.
false

例如,原子本身按词法排序(即z的值大于a值)(请参见清单12 )。

清单12.按词法排序的原子
13> a < z.
true

标准布尔运算符可用,例如and orxornot 。 您还可以使用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'}

这里的标签是电子邮件,标签可用于帮助识别元组中其余的内容。

元组对于包含定义的元素和描述不同的复杂数据结构非常有用,Erlang允许您显式setget元组中的值(请参见清单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.使用双引号引起来的值创建一个字符串值
23> "Hello".
"Hello"

但是,字符串实际上只是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"]

列表模块中提供了许多用于操作列表的功能。例如,您可以使用排序功能对列表中的项目进行排序。 由于这些是内置函数,因此必须指定模块和函数名称(请参见清单21 )。

清单21.指定模块和函数名称
34> lists:sort([4,5,3,2,6,1]).
[1,2,3,4,5,6]

列表操作

您可以使用构造函数构造具有多个元素的列表,该构造函数从一个元素和另一个列表构建一个列表。 换句话说,这种构造是由push()函数或运算符处理的。 在Erlang中, | (pipe)运算符用于用符号[Head|Tail]区分头(列表的开头)和[Head|Tail] 。 这里的头是单个元素,而尾部是列表的其余部分。

清单22显示了如何向列表的开头添加新值。

清单22.在列表的开头添加一个新值
29> [1|[2,3]].
[1,2,3]

您可以对整个列表重复此操作,如清单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中的变量
41> Value = 99.
99

在Erlang中分配变量是将值一次性绑定到变量。 一旦绑定了变量一次,就无法更改其值(请参见清单29 )。

清单29.将值绑定到变量
42> Value = 100.
** exception error: no match of right hand side value 100

这与大多数语言不同-变量的定义往往意味着值是变量。 单一赋值意味着,如果要计算值的结果,则必须将其赋给新变量(请参见清单30 )。

清单30. Erlang中变量的限制
43> Sum = Value + 100
199

这种单一分配的好处在于,它使得在计算过程中引入或意外更改变量的值变得更加困难,这使得在编程过程中识别值和调试变得更加容易。 它还可以使代码更清晰,有时甚至更短,因为您可以简化结构。

请注意,此操作意味着将值绑定到变量之前先进行计算。 在其他语言中,可以根据对函数或操作的引用来设置值,这意味着值可以根据访问时引用的值而有所不同。 在Erlang中,变量的值在创建时始终是已知的。

您可以使用f(Varname)显式忘记变量的边界,或者使用f()显式忘记所有变量的边界。

将值分配给变量实际上是模式匹配的一种特殊类型。 Erlang中的模式匹配还处理单个语句的执行流程,并从复合数据类型(元组,数组)中提取单个值。 因此,模式匹配的基础是:模式=表达式。

该表达式由数据结构,绑定变量(即具有值的变量),数学运算和函数调用组成。 操作的两侧必须匹配(也就是说,如果您将2个元素元组作为模式,则表达式必须解析为2个元素元组)。 执行表达式时,将对表达式求值,并将结果分配给模式。

例如,我们可以通过一个模式匹配将值同时分配给两个变量(参见清单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

必须在文件的模块内定义功能(不能从外壳程序内定义功能)。 参数可以包含更复杂的类型。 例如,元组中的标签可用于选择不同的操作(请参见清单33 )。

清单33.元组中的标记可用于选择不同的操作
mathexp({sum, N,M}) -> N+M ;
mathexp({sub, N,M}) -> N-M ;
mathexp({square, N}) -> N*N.

分号是每个函数定义之间的或运算符。 模式匹配用于评估函数的参数,因此,如果为mathexp()函数提供一个包含三个元素的元组,则模式匹配将失败。

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()包含要导出的功能列表。 每个函数的定义显示函数名称以及该函数的含义。 这使您能够导出功能的非常特定的定义。

要使用该模块,需要对其进行编译和加载。 您可以使用c()语句在外壳中执行此操作,如清单35所示。

清单35.使用c()语句编译和加载模块
1> c(fib).
{ok,fib}
2> fib:printfibo(9).
9 34
ok

请注意,该函数调用包含模块名称,以确保我们在fib模块内调用printfibo()函数。

结论

Erlang程序的结构和格式与大多数其他语言完全不同。 尽管许多数据类型和基本表达式相同,但是它们的使用和应用略有不同。 一次性使用变量以及通过模式匹配系统证明的评估不同表达式的重要性为典型的语言环境提供了强大的扩展。 例如,为同一功能定义多种方法并为递归调用采用模式匹配的功能可简化某些功能。

下次,我们将研究Erlang的过程,消息解析和网络设施,并查看MochiWeb HTTP服务器,以了解该语言的功能和灵活性。


翻译自: https://www.ibm.com/developerworks/opensource/library/os-erlang1/index.html

基础知识

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值