erLang中的标点符号
ErLang中的标点符号
ErLang语法中充满了一些约定。大写字母开头的名字(比如Address),表示一个变量,包括参数、局部变量等;小写字母开头的单词(比如ok),表示一个常量,叫做atom(原子的意思),包括常量名、函数名、模块名等。
ErLang的注释用%开头。ErLang用下划线“_”表示任意变量,类似于Java的switch语法里面的default选项。
ErLang脱胎于Prolog,不过,我觉得,ErLang语法和Haskell语法比较象,都是采用 -> 定义函数。
ErLang语句中的标点符号用法很象文章的标点符号。
整个函数定义结束用一个句号“.”;同一个函数中,并列的逻辑分支之间,用分号“;”分界;顺序语句之间,用逗号“,”分隔。
ErLang中,{ }不是表示程序块的开头和结尾,而是表示一种特殊的数据结构类型——Tuple(元组),比如,{12, 3, ok}。我们可以把Tuple理解为定长数组。
[ ] 则表示最基本的函数式编程的数据结构类型——List。List数据结构很基本,写法和用法也有一定的复杂度,不是表面上看起来那么简单,后面讲解Closure的章节会详细介绍List的最基本的构造原理。
下面我们来看一个简单的例子。
我们首先定义一个最简单的函数,把一个参数乘以10,然后加1。
times10( Number ) –>
Temp = 10 * Number,
Temp + 1.
为了说明问题,上面的代码把乘法操作和加法操作分成两个步骤。Temp = 10 * Number语句后面是逗号,因为这是两条顺序执行的语句。 Temp + 1语句后面是句号,表示整个函数定义结束。而且,可以看出,ErLang没有return语句,最后执行的那条语句的执行结果就是返回 值。
下面,我们把这个函数优化一下。当参数等于0的时候,直接返1;否则,就乘以10,然后加1,然后返回。这时候,我们就要用到case of逻辑分支语句,相当于java的switch语句。
times10( Number ) –>
case Number of
0 -> 1;
_ ->
Temp = 10 * Number,
Temp + 1
end.
我们来仔细观察这段ErLang程序。
当Number等于0的时候,直接返回1。由于这是一条分支语句,和后面的分支是并列的关系,所以,1的后面的标点符号是分号。后面这个分支,下划线“_”表示任何其它值,这里就表示除了1之外的任何其它数值。
需要注意的一点是,case of语句需要用end结尾,end之前不需要有标点符号。
上述代码中的case of 语句,其实就是Pattern Match的一种。ErLang的Pattern Match很强大,能够大幅度简化程序逻辑,后面进行专门介绍。
Pattern Match
Pattern Match主要有两个功能——比较分派和变量赋值。
其中,比较分派是最主要的功能。比较分派的意思是,根据参数值进行条件分支的分派。可以把比较分派功能看作是一种类似于if, else等条件分支语句的简洁强大写法。
上面的例子中,case Number of 就是根据Number的值进行比较分派。更常见的写法是,可以把Pattern Match部分提到函数定义分支的高度。于是,上述代码可以写成下面的形式:
times10( 0 ) –> 1;
times10( Number ) –>
Temp = 10 * Number,
Temp + 1.
这段代码由两个函数定义分支构成,由于两个函数分支的函数名相同,而且参数个数相同,而且两个函数定义分支之间采用分号“;”分隔,说明这是同一个函数的定义。函数式编程语言中,这种定义方式很常见,看起来形式很整齐,宛如数学公式。
这段代码的含义是,当参数值等于0的时候,那么,程序走第一个函数定义分支(即分号“;”结尾的“times10( 0 ) –> 1;”),否则,走下面的函数定义分支(即“times10( Number ) –>…”)。
第二个分支中的参数不是一个常数,而是一个变量Number,表示这个分支可以接受任何除了0之外的参数值,比如,1、2、12等等,这些值将赋给变量Number。
因此,这个地方也体现了Pattern Match的第二个功能——变量赋值。
Pattern Match的形式可以很复杂,下面举几个典型的例子。
(1)数据结构拆解赋值
前面将到了ErLang语言有一种相当于定长数组的Tuple类型,我们可以很方便地根据元素的位置进行并行赋值。比如,
{First, Second} = {1, 2}
我们还可以对复合Tuple数据结构进行赋值,比如
{A, {B, C}, D} = { 1, {2, 3}, 4 }
List数据结构的赋值也是类似。由于List的写法和用法不是那么简单,三言两语也说不清楚,还徒增困扰,这里不再赘述。
(2)assertEquals语句
在Java等语言中,我们写单元测试的时候,会写一些assert语句,验证程序运行结果。这些assert语句通常是以API的方式提供,比如,assertTrue()、assertEquals()等。
在ErLang中,可以用简单的语句达到类似于assertTrue()、assertEquals()等API的效果。
比如,ErLang中,true = testA() 这样的语句表示testA的返回结果必须是true,否则就会抛出异常。这个用法很巧妙。这里解释一下。
前面讲过,ErLang语法约定,小写字母开头的名字,都是常量名。这里的true自然也是一个常量,既然是常量,我们不可能对它赋值,那么true = testA()的意思就不是赋值,而是进行匹配比较。
(3)匹配和赋值同时进行
我们来看这样一段代码。
case Result of
{ok, Message} -> save(Message);
{error, ErrorMessage} -> log(ErrorMessage)
end.
这段代码中,Result是一个Tuple类型,包含两个元素,第一个元素表示成功(ok)或者失败(error),第二个元素表示具体的信息。
可以看到,这两个条件分支中,同时出现了常量和变量。第一个条件分支中的ok是常量,Message是变量;第二个条件分支中的error是常量,ErrorMessage是变量。
这两个条件分支都既有比较判断,也有变量赋值。首先,判断ResultTuple中的第一个元素和哪一个分支的第一个元素匹配,如果相配,那么把 ResultTuple中的第二个元素赋给这个分支的第二个变量元素。即,如果Result的第一个元素是ok,那么走第一个条件分支,并且把 Result的第二个元素赋给Message变量;如果Result的第二个元素是error,那么走第二个条件分支,并且把Result的第二个元素赋 给ErrorMessage变量。
在Java等语言中,实现上述的条件分支逻辑,则需要多写几条语句ErLang语法可以从形式上美化和简化逻辑分支分派复杂的程序。
除了支持数相等比较,Pattern Match还可以进行范围比较、大小比较等,需要用到关键字when,不过用到when的情况,就比if else简洁不了多少,这里不再赘述。
匿名函数
ErLang允许在一个函数体内部定义另一个匿名函数,这是函数式编程的最基本的功能。这样,函数式语言才可以支持Closure。我们来看一个ErLang的匿名函数的例子。
outer( C ) –>
Inner = fun(A, B) -> A + B + C end,
Inner(2, 3).
这段代码首先定义了一个命名函数outer,然后在outer函数内部定义了一个匿名函数。可以看到,这个匿名函数采用关键字fun来定义。前面讲过,函 数式编程的函数就相当于面向对象编程的类实例对象,匿名函数自然也是这样,也相当于类实例,我们可以把这个匿名函数赋给一个变量Inner,然后我们还可 以把这个变量当作函数来调用,比如,Inner(2, 3)。
fun是ErLang用来定义匿名函数的关键字。这个关键字很重要。fun定义匿名函数的用法不是很复杂,和命名函数定义类似。
函数分支的定义也是类似,只是需要用end结尾,而不是用句号“.”结尾,而且fun只需要写一次,不需要向命名函数那样,每个分支都要写。比如,
MyFunction = fun(0) -> 0;
(Number) -> Number * 10 + 1 end,
MyFunction(3),
函数作为变量
匿名函数可以当作对象赋给变量,命名函数同样也可以赋给变量。具体用法还是需要借助重要的fun关键字。比如,
MyFunction = fun outer / 1
就可以把上述定义的outer函数赋给MyFunction变量。后面的 / 0表示这个outer函数只有一个参数。因为ErLang允许有多个同名函数的定义,只要参数个数不同,就是不同的函数。
我们可以看到,任何函数都可以作为变量,也可以作为参数和返回值传来传去,这些变量也可以随时作为函数进行调用,于是就具有了一定的动态性。
函数的动态调用
ErLang有一个apply函数,可以动态调用某一个函数变量。
基本用法是 apply( 函数变量,函数参数列表 )。比如,上面的MyFunciton函数变量,就可以这么调用,apply( MyFunction, [ 5 ])。
那么我们能否根据一个字符串作为函数名获取一个函数变量呢?这样我们就可以根据一个字符串来动态调用某个函数了。
ErLang中,做到这一点很简单。前面讲过,函数名一旦定义了,自然就固定了,这也类似于常量名,属于不可变的atom(原子)。所有的atom都可以 转换成字符串,也可以从字符串转换过来。ErLang中的字符串实质上都是List。字符串和atom之间的转换通过list_to_atom和 atom_to_list来转换。
于是我们可以这样获取MyFunciton:MyFunction = list_to_atom(“outer”)
如果outer函数已经定义,那么MyFucntion就等于outer函数,如果outer函数没有定义,那么list_to_atom(“outer”)会产生一个新的叫做outer的atom,MyFucntion就等于这个新产生的atom。
如果需要强制产生一个已经存在的atom,那么我们需要调用list_to_existing_atom转换函数,这个函数不会产生新的atom,而是返回一个已经存在了的atom。
Tuple作为数据成员集合
前面讲解函数式编程特性的时候,提到了函数式编程没有面向对象编程的成员变量,这是一个限制。
ErLang的Tuple类型可以一定程度克服这个限制。Tuple可以一定程度上担当容纳成员变量的职责。
面向对象的类定义,其实就是一群数据和函数的集合,只是集合的成员之间都有一个this指针相关联,可以相互找到。
ErLang的Tuple类型就是数据的集合,可以很自然地发挥成员变量的作用,比如,{Member1, Member2}。
读者可能会说,ErLang的函数也可以作为变量,也可以放到Tuple里面,比如, { Memer1, Member2, Funtion1, Function2}。这不就和面向对象编程一样了吗?
遗憾的是,这样做是得不偿失的。因为函数式编程没有面向对象的那种内在的this指针支持,自然也没有内在的多态和继承支持,硬把数据和函数糅合在一个Tuple里面,一点好处都没有,而且还丧失了函数作为实例对象的灵活性。
所以,函数式编程的最佳实践(Best Practice)应该是:Tuple用来容纳成员数据,函数操作Tuple。Tuple定义和函数定义加在一 起,就构成了松散的数据结构,功能上类似于面向对象的类定义。Tuple + 函数的数据结构,具有多态的特性,因为函数本身能够作为变量替换;但是不具 有继承的特性,因为没有this指针的内在支持。
正是因为Tuple在数据类型构造方面的重大作用,所以,ErLang专门引入了一种叫做Record的宏定义,可以对Tuple的数组下标位置命名。比 如,把第一个元素叫做Address,第二个元素叫做Zipcode,这样程序员就可以这些名字访问Tuple里面的元素,而不需要按照数组下标位置来访 问。
Tuple和Record的具体用法还是有一定复杂度,限于篇幅,本章没有展开说明,只提了一些原理方面的要点。
其它
ErLang还有其它语法特性和细节,不再一一赘述。有兴趣的读者,可以自行去ErLang网站(www.erlang.org)进行研究。
erLang中的标点符号相关推荐
- Erlang中Eunit基本内容汇总
Erlang中Eunit基本内容汇总 在你的module中添加: -include_lib("eunit/include/eunit.hrl"). 这样就引入了eunit的头文件, ...
- string对象中去掉标点符号
C++ Primer 4th Edition,P78,习题3.10 题目要求:编写一个程序,从string对象中去掉标点符号.要求输入到程序的字符串必须必须包含标点符号,输出结果则是去掉标点符号后的s ...
- Erlang中一些错误或者异常的标识
erlang中错误大体分为四种: 1. 编译错误 2. 逻辑错误 3. 运行时错误 4. 用户代码生成的错误 编译错误,主要是编译器检测出的代码语法错误 逻辑错误,是指程序没 ...
- 【Java】高效处理字符串中的标点符号
[Java]清洗字符串中的标点符号 去除字符串中的所有标点符号 \pP 其中的小写 p 是 property 的意思,表示 Unicode 属性,用于 Unicode 正表达式的前缀. 大写 P 表示 ...
- WORD精灵:将Word文档中的标点符号统一为全角或者半角
WORD精灵:将Word文档中的标点符号统一为全角或者半角 将Word文档中的标点符号统一为全角或者半角,比手工操作高效百倍
- 如何批量删除word中的中文和标点符号(word删除中文所有标点符号)
如何批量删除word中的中文和标点符号(word删除中文所有标点符号) 当文档中前面一列英文,后面一列汉字的时候,你还在一个一个的去删除汉字吗?那样也太慢了.快快看看下面介绍的几种方法,绝对会大大提高 ...
- erlang 中#(井号)号的作用
表示进制 10> 2#101010. %% 2 进制的 101010 42 11> 8#0677. %% 8 进制的 0677 447 12> 16#AE. %% 16 进制的 AE ...
- python不允许标点符号_python3去掉string中的标点符号方法
网上看到的python去掉字符串中的标点符号的方法,大多是基于python2的,不适用python3,调整后代码如下: 代码 lower_case_documents = ['Hello, how a ...
- python并且符号_Python如何从文字中分离标点符号
所以我想用空格将文本与标点符号分开.Python如何从文字中分离标点符号 my_text = "!where??and!!or$$then:)" 我想要有一个! where ?? ...
最新文章
- ServiceMesh有关sidecar理解
- JavaScript速记
- 0001242: Steps to make RealTek DVB-T USB dongle...
- A、B、C、D、E五人在某天夜里合伙去捕鱼,到第二天凌晨时都疲惫不堪
- 如何通过css控制内容显示顺序 第二行的内容优先显示
- 总结:第一章~第五章
- NetApp集群模式Data ONTAP展露新颜
- Spring 系统学习:Spring的事务管理---事务回顾
- 洛谷——P2084 进制转换
- CAD入门教程,基本设置,使用技巧
- js调用数科阅读器_多种方式实现JS调用后台方法进行数据交互
- javascript中正则匹配多个条件, 常用正则匹配, 正则详解
- (一)阿里云创建自己的产品和设备
- 利用文心大模型制作多功能机器人
- UG\NX二次开发 获取UG窗口句柄。实现操作UG窗口最小化、最大化、关闭功能
- Coin-row problem
- HTML5新特性之History
- 免杀学习——PHP免杀
- Maya动画1:基础知识小球弹跳
- 红领巾小创客机器人活动计划_争当红领巾小创客--小创客 大梦想