Erlang的交互式环境
安装:下载并安装Erlang,在OS的环境变量中添加pathErlangHOME/bin目录
启动:linux 环境:erl,windows: 开始-程序-erlang图标启动(或像linux输入erl在CMD模式下启动)
当然也可以在图标模式下启动,把源代码放在另一个目录中,要调用则要更改目录,例如:1> cd("d:/program/Erlang").d:/program/Erlang ok .
退出:Ctrl+C 或者 halt().
Erlang shell:
shell中会打印出1>,2>类似的行号
%表示注释,例如:1>% I'm going to enter some expressions in the shell.. 注释不会被Erlang编译
在shell中直到你在表达式的末尾敲入一个结束符行号才不会一直显示当前的行号,结束符是点号(.)
在shell中当你打入一个括号('(','{','[')符的结束符时,shell会提示你起始符的位置,然后再继续输入
当shell对你的指令没反映的时候,你可以按入Ctrl+C中断,系统会提示:BREAK:(a)bort (c)ontinue 等
你可以同时打开多个shell窗口
变量:
所有的变量首字母应为大写字母,小写开头不是变量。1>X = 123456. 123456 ; 2>Xyz = 12345.
定义变量后,不能再给变量赋予另外的值,否则会出错 1>X = 123. 2>X=234. (出错)原文:Erlang has single assignment variables.
变量类型:
整型 : erlang支持任意大小的整型数进行运算,你不用担心它会溢出、错误或者在一个字的大小内能否表示等问题。
例 如:11> 123456789*987654321*112233445566778899*998877665544332211. = 13669560260321809985966198898925761696613427909935341
还可以用2#,8#,16#,32#(最大)等进制进行算术,如: 1>2#11110000 * 2#00001111. = 3600 ,即10进制的240 * 15
1>8#7 * 8#6. = 42 ,即 10进制的7*6 = 42 ; 1>16#a * 16#b. = 110 16进制的a=10,b=11,结果即110。
浮点类型:除法 5/3 = 1.66667 4/2=2.00000 , "/"永远返回浮点型; 商 5 div 3=1 , 4 div 2 = 2 ;余数 5 rem 3 = 2 , 整数与浮点数进行运算,结果是浮点数
小技巧:f().方法会遗忘变量绑定的值,即可对一个变量多次赋值,此命令危险,是所有变量都遗忘。
atom类型(元子类型):原子类型是全局的,以小写字母打头,不同于变量的大写。元子只是一个简单的名字,其它什么都不是,他们不像变量一样可以带有值。如果您的程序中有一个参数是元子类型,如果你传入不相同的元子则程序出错
Tuples类型(元组类型,python语言中有):类似C语言中的结构体。Tuples具有垃圾自动回收功能,能自动释放不用的内存,在 Tuples中,符号"_(下划线)"可以取任何变量值,不像有符号的变量,“_”不会出错但也不绑定值。Tuples类型以“{”开头,以”}“结尾。
Lists类型(列表类型):可以使用lists类型存储任何数量的变量.lists变量以"["打头,"]"结尾。Lists类型中可以有Tuples类型. 例如:[1+7,apples,{abc,10},123]
lists类型中如果有表达式的话,输出的结果是表达式的值。如[1+7,20-20] 结果为[8,0]。
如果T是一个LIST类型,则[H|T]永远是LIST类型, []代表一个空list,"|"表示分隔。
也可以从一个LIST中把值赋与一批元素变量类似:[Buy1|ThingsToBuy2] = ThingsToBuy1.也可以表“|”进行分隔,“|”前buy1对应一个元素,“|“后面的对应多个元素。
小结:可以把一批值放到LIST中,也可以把一批值给予一批变量,也可以用”|“进行有需求的分隔List。
Strings类型:严格的说在Erlang中没有Strings类型,Strings类型仅仅是list与整型。Strings是用双引号(“”)标识的
Strings 类型也可以用LIST来表示,例如:[83,117,114,112,114,105,115,101].会表示出:"Surprise",但 [1,2,3]还是会表示出[1,2,3],因为1-31都不是可打印字符,如果一个list有一个元素不是可打印字符则list不用string输出
小技巧:在Erlang中,可以用“$"符(美元符)来表示一个字母的整型值,例$s = 115,上面的则可以用[I-32,$u,$r,$p,$r,$i,$s,$e].来形象的表示
符号的作用:
=号:
在大多数语言中,=号是一个赋值语句,但在Erlang中,不管怎么样=都是一个模式匹配操作。例:X=(2+4). 与X=6.这两句不会出错,因为X=6是值进行匹配,如果X=(2+4). X=3.这两句一起执行就会出错,因为6不等于3。
百分号(%) ,注释符%% this is commet
逗号(, comma) ,分隔函数的参数,数据结构或者模式匹配
点号(.period), 在shell中用以标识整个函数与表达式的结尾
分号(;semicolon) ,分割模块中的子句,一个函数中有多个相同的重载方法,则用分号分隔。 在case,if,try..catch,receive出现
竖 线("|") 遍历列表的方法,|运算后通常得到list的第一个元素。如[First|TheRest] = [1,2,3,4,5],First=1,TheRest=[2,3,4,5].当然在|前加上值可以把list变的更长,可以由空变成一个list,例 如把list反转就可以应用此方法。
符号“||”(双竖线)用来表示comprehensions操作。
=:= (值相等),判断两个值是否相等,类似JAVA中的==
<(小于) >(大于) =< (等于小于) ,>=(大于等于) , /=(不等于)
_(下划线) ,匿名变量,这是一个简化的,用于一个将得到值的变量,并且我们还需要丢弃这个值的情况下使用
modules(模块)
模块是Erlang代码的基本单元。所有的函数将封装在模块中,模块以后缀为.erl的文件形式进行存储。模块在运行前必须被编译,编译模块为.beam文件
一个简单的模块geometry.erl
-module (geometry).
-export([area/1]).
area( {rectangle , Width ,Ht} ) ->Width * Ht ;
area( {circle,R } ) -> 3.14159 * R * R .
分析:
-module(filename) 指出模块的名字,注意filename要与文件名一样,类似JAVA
-export([area/1])指出模块有一个名为area的函数,并且带有一个参数,模块中的方法area可以在其它模块被调用。也可以带多个参数,比如-expot([area/1,mult/2]).
-import(lists,[map/2,sum/1]). 表示从外部引用模块的方法,这句就引用了模块lists中的两个方法,map与sum
area有两个字句,字句之间用分号(;)进行间隔, 结尾用(.)点号结束。两个字句的参数均为tuple类型,tuple中有几个参数则执行哪个子句
编译modules模块:
1、新建一个.erl的文件,启动erl
2、输入c(filename) 进行编译,注意c是小写,filename是函数名,函数名必须与erl的文件名一样,编译后会产生一个文件:filename.beam
3、执行erl文件中的方法 filename:functionname(para) 分别是文件名:函数名(参数)
4、如果有多个模块在多个不同的文件中,把文件编译后在同一目录下可以直接输入filename名进行function引用。
个人小结:个人认为erlang环境做的最多的就是自动迭代与递归。例如[{M}|T],如果list参数有10个tuple,你只需用一条语句fn(M) + fn(T),则Erlang环境自动把参数拆解并迭代递归调用,直到程序完成。
内建函数(BIFs)
内建函数是一个因为某原因被内嵌在Erlang虚拟机中的函数。BIFs经常是一些在Erlang上无法实现或者实现起来效率不高的东西,默认属于Erlang摸块下,比如trunc与erlang:trunc调用等同
可以用于条件判断(守卫)的内建函数举例:
trunc(5.6). : 5 (去小数点)
round(5.6). : 6 (四舍五入)
length([a,b,c,d]). : 4 (list求元素个数)
float(5). : 5.00000 (整形变成浮点型)
is_atom(hello). : true (判断是否元子类型)
is_tuple({abc,{1,30}}). : true (判断是否元组类型)
以下的内建函数不能用于守卫,比如:
atom_to_list(hello). : "hello" (元子类型转list)
list_to_atom("bye"). : bye (list类型转元子)
integer_to_list(22). : "22" (整型转list类型)
以上三个内建函数很难(不可能)在Eralng中实现
Funs(复杂函数) :
funs是一个匿名的函数,只所以这么称呼是因为这个函数没有名字,但可以把函数指向一个变量,类似C中指向函数的指针。
例如:Z = fun(X) -> 2*X end. fun(X)是一个匿名函数,函数的主体是2*X ,把函数指向了变量Z,执行Z(2) = 4,即2*2 = 4.
fun(X) 中的参数X可以为tuple,list,甚至还可以像C中的switch用多个参数,例如:fun(C,C) ->xxxxx ; (f,F) ->xxxxx ; (y,Y)->xxxx end.参数要对应匹配,传递的参数与申明的不一样则抛出异常。
小技巧:lists 是Erlang的标准库。有两个有用的方法:lists:map(F,L)和lists:fliter(F,L),F:Funs,L:list对象。 map的功能是把L用F进行处理后返回一个新的List,Fliter的作用是把L按照F的方法进行过滤返回一个新List
例:L=[1,2,3,4] ,lists:map(Double,L) = [2,4,6,8]. Double = Fun(X) -> X * 2 end. 对于Fliter,如果经过运算得到的某一项的值为Flase则丢弃原List值。
Funs还可以进行嵌套,即一个函数返回一个fun对象,例如:Mu = fun(X) -> ( fun(Y) -> X * Y end) end. Tr = Mu(5) ;Tr(3) = 15.
我们还可以这样使用fun ,例:lists:map(fun convert_to_c/1,List). 这句fun中是定义别处的一个函数,可以通过函数名/参数个数来使用
List Comprehensions (list 理解):
List comprehensions 即对list操作不使用funs,maps或者fliters等方法而实现对应功能的表达式。符号“||”(双竖线)用来表示comprehensions操作。
以 往的操作都是比如L=[1,2,3,4,5] ;lists:map(fun(X) -> X*2 end,L).实现[2,4,6,8,10],这些方式过于繁琐,可以使用[F(X) || X<-L] 来实现,F(X)的意思是List中的每一个项都给变量X,前面的例子因此可以简写成[2*X || X <- L] =[2,4,6,8,10],即把L中的每一个元素给X然后乘以2。这里的X变量只是临时的,语句过后X的值不存在,如果前面有语句已经定义X,则 Erlang不会抛错,X只适用于该语句。
再看这个例子:[X || {a,X} <- [{a,1},{b,2},{c,3},{a,4},hello,"WOW"] ].这个例子得到的值是[1,4],为什么是list[1,4]呢?因为原子a在list中有两个,因此得到1,4.
List Comprehensions的超强应用,超简单排序算法:
qsort([Pre|Nex]) -> qsort([X || X <- Nex , X <Pre]) // 一个list,经过[pre|Nex]运算后,得到pre的值,只取比pre小的值放前面,
++ [Pre] ++ // ++ 是list的连接操作符,语句产生的list前后加起来
qsort([X || X <- Nex , X>=Pre]). //一个list ,经过[pre|Nex]运算后,得到pre的值,只取比pre大的值放后面,然后erlang自动迭代递归,直到List中的最后一个值,排序完成,3 行完成一个排序算法
IF语句
示例:
test_if(A,B) ->
Result = if
B == 6 -> io:format("B= 6~n",[]) , b_equals_6 ;
A == 5 -> io:format("A= 5~n",[]) , a_equals_5 ;
A == 2 , B == 3 -> io:format("A==2 , B==3 ~n",[]) , a_equals_2_b_equals_3;
A == 1 ; B == 7 -> io:format("A==1 ; B == 7 ~n",[]),a_equals_1_or_b_equals_7;
true -> nothging
end.
说明:
1/if 与 end. (注意点号匹配)
2/每条if语句后面带分号(;),最后一条没有,且每条if语句都有隐性的break功能,执行完后将退出if语句
3/第一条判断将最先匹配
4/A==2 ,B ==3 中间的逗号表示 AND
5/A==1 ;B== 7 中间的分号表示 OR
6/if语句中直接写元了类型将直接输出元子
7/输入的条件都不匹配的将抛出(if_clause)异常,除非最后有一句true
8/if与case语句都可有返回值,上例中如果值为true,则Result的值为元子nothing.
CASE语句:
例:
case Length of
{centimeter ,X} -> {inch,X / 2.54};
{inch,Y} -> {centimeter,Y * 2.54 };
end.
说明:
1/case of end.匹配
2/可以用元组类型(tuples)进行判断
3/都带有隐性的break功能。
4/if与case语句都可有返回值