Erlang入门(一)

  读erlang.org上面的Erlang Course四天教程
1.数字类型,需要注意两点
1)B#Val表示以B进制存储的数字Val,比如

7> 2#101.
5

二进制存储的101就是10进制的5了
2)$Char表示字符Char的ascii编码,比如$A表示65

2.比较难以翻译的概念——atom,可以理解成常量,它可以包含任何字符,以小写字母开头,如果不是以小写字母开头或者是字母之外的符号,需要用单引号包括起来,比如abc,'AB'

3.另一个概念——Tuple,有人翻译成元组,可以理解成定长数组,是Erlang的基础数据结构之一:

8> {1,2,3,4,5}.
{1,2,3,4,5}
9> {a,b,c,1,2}.
{a,b,c,1,2}
10> size({1,2,3,a,b,c}).
6

内置函数size求长度,元组可以嵌套元组或者其他结构。下面所讲的列表也一样。

4.另外一个基础数据结构就是各个语言都有的list(列表),在[]内以,隔开,可以动态改变大小,

    [123, xyz]
    [123, def, abc]
    [{person, 'Joe', 'Armstrong'},
        {person, 'Robert', 'Virding'},
        {person, 'Mike', 'Williams'}
    ]

可以使用内置函数length求列表大小。以""包含的ascii字母代表一个列表,里面的元素就是这些字母的ascii值,比如"abc"表示列表[97,98,99]。

5.通过这两个数据结构可以组合成各种复杂结构,与Lisp的cons、list演化出各种结构一样的奇妙,Erlang也可以当作是操作列表的语言。

6.Erlang中变量有两个特点:
1)变量必须以大写字母或者下划线开头,可以包含字母、下划线和@
2)变量只能绑定一次,也就是所谓的Single Assignment。或者以一般的说法就是只能赋值一次,其实Erlang并没有赋值这样的概念,=号也是用于验证匹配。

7.模式匹配——Pattern Matching,Erlang的模式匹配非常强大,看了buaawhl的《Erlang语法提要》的介绍,模式匹配的功能不仅仅在课程中介绍的数据结构的拆解,在程序的分派也扮演重要角色,或者说Erlang的控制的流转是通过模式匹配来实现的。具体功能参见链接,给出书中拆解列表的例子:

    [A,B|C] = [1,2,3,4,5,6,7]
        Succeeds - binds A = 1, B = 2,
        C = [3,4,5,6,7]
    
    [H|T] = [1,2,3,4]
        Succeeds - binds H = 1, T = [2,3,4]
    
    [H|T] = [abc]
        Succeeds - binds H = abc, T = []
    
    [H|T] = []
        Fails

下面会给出更多模式匹配的例子,给出一个模块用来计算列表等

8.Erlang中函数的定义必须在一个模块内(Module),并且模块和函数的名称都必须是atom,函数的参数可以是任何的Erlang类型或者数据结构,函数要被调用需要从模块中导出,函数调用的形式类似:
moduleName:funcName(Arg1,Arg2,...).
写我们的第一个Erlang程序,人见人爱的Hello World:

-module(helloWorld).
-export([run/1]).
run(Name)->
    io:format("Hello World ~w~n",[Name]).

存为helloWorld.erl,在Erlang Shell中执行:

2> c(helloWorld).
{ok,helloWorld}
3> helloWorld:run(dennis).
Hello World dennis
ok

打印出来了,现在解释下程序构造,

-module(helloWorld).

这一行声明了模块helloWorld,函数必须定义在模块内,并且模块名称必须与源文件名相同。

-export([run/1]).

而这一行声明导出的函数,run/1指的是有一个参数的run函数,因为Erlang允许定义同名的有不同参数的多个函数,通过指定/1来说明要导出的是哪个函数。
接下来就是函数定义了:

run(Name)->
    io:format("Hello World ~w~n",[Name]).

大写开头的是变量Name,调用io模块的format方法输出,~w可以理解成占位符,将被实际Name取代,~n就是换行了。注意,函数定义完了要以句号.结束。然后执行c(helloWorld).编译源代码,执行:

helloWorld:run(dennis);

9.内置的常用函数:

    date()
    time()
    length([1,2,3,4,5])
    size({a,b,c})
    atom_to_list(an_atom)
    list_to_tuple([1,2,3,4])
    integer_to_list(2234)
    tuple_to_list({})
    hd([1,2,3,4])  %输出1,也就是列表的head,类似Lisp的car
    tl([1,2,3,4])  %输出[2,3,4],也就是列表的tail,类似List的cdr

10.常见Shell命令:
1)h(). 用来打印最近的20条历史命令
2)b(). 查看所有绑定的变量
3) f(). 取消(遗忘)所有绑定的变量。
4) f(Val).  取消指定的绑定变量
5) e(n).   执行第n条历史命令
6) e(-1).  执行上一条shell命令

11.又一个不知道怎么翻译的概念——Guard。翻译成约束?呵呵。用于限制变量的类型和范围,比如:

     number(X)    - X 是数字
    integer(X)    - X 是整数
    float(X)    - X 是浮点数
    atom(X)        - X 是一个atom
    tuple(X)    - X 是一个元组
    list(X)        - X 是一个列表
    
    length(X) == 3    - X 是一个长度为3的列表
    size(X) == 2    - X 是一个长度为2的元组
    
    X > Y + Z    - X >Y+Z
    X == Y        - X 与Y相等
    X =:= Y        - X 全等于Y
    (比如: 1 == 1.0 成功
               1 =:= 1.0 失败)

为了方便比较,Erlang规定如下的比较顺序:

number < atom < reference < port < pid < tuple < list

其中pid就是process的id。

12.忘了介绍apply函数,这个函数对于熟悉javascript的人来说很亲切,javascript实现mixin就得靠它,它的调用方式如下:

apply(Mod, Func, Args),三个参数分别是模块、函数以及参数列表,比如调用我们的第一个Erlang程序:

apply(helloWorld,run,[dennis]).

13.if和case语句,if语句的结构如下:
if
Guard1 ->
Sequence1 ;
Guard2 ->
Sequence2 ;
...
end
而case语句的结构如下:

case Expr of
Pattern1 [when Guard1] -> Seq1;
Pattern2 [when Guard2] -> Seq2;

PatternN [when GuardN] -> SeqN
end

if和case语句都有一个问题,就是当没有模式匹配或者Grard都是false的时候会导致error,这个问题case可以增加一个类似java中default的:

case Fn of

   _ ->
   true
end

通过_指代任意的Expr,返回true,而if可以这样:

if
  
  true ->
   true
end

一样的道理。case语句另一个需要注意的问题就是变量范围,每个case分支中定义的变量都将默认导出case语句,也就是在case语句结束后可以被引用,因此一个规则就是每个case分支定义的变量应该一致,不然算是非法的,编译器会给出警告,比如:

f(X) ->
case g(X) of
true -> A = h(X), B = A + 7;
false -> B = 6
end,
h(A).

如果执行true分支,变量A和变量B都被定义,而如果执行的false分支,只有变量B被定义,可在case语句执行后,h(A)调用了变量A,这是不安全的,因为变量A完全可能没有被定义,编译器将给出警告
variable 'A' unsafe in 'case' (line 10)

14.给出一些稍微复杂的模型匹配例子,比如用于计算数字列表的和、平均值、长度、查找某元素是否在列表中,我们把这个模块定义为list:

-module(list).
-export([average/1,sum/1,len/1,double/1,member/2]).
average(X)->sum(X)/len(X).
sum([H|T]) when number(H)->H+sum(T);
sum([])->0.
len([_|T])->1+len(T);
len([])->0.
double([H|T]) -> [2*H|double(T)];
double([]) -> [].
member(H, [H|_]) -> true;
member(H, [_|T]) -> member(H, T);
member(_, []) -> false.
                

细细体会,利用递归来实现,比较有趣,这其实与Lisp中利用尾递归来实现迭代是一样的道理,[H|T]的形式类似Lisp中的car、cdr操作。_用于指代任意的变量,当我们只关注此处有变量,但并不关心变量的值的时候使用。用分号;来说明是同一个函数定义,只是不同的定义分支,通过模式匹配来决定调用哪个函数定义分支。
另一个例子,计算各种图形的面积,也是课程中给出的例子:

-module(mathStuff).
-export([factorial/1,area/1]).
factorial(0)->1;
factorial(N) when N>0->N*factorial(N-1).
%计算正方形面积,参数元组的第一个匹配square    
area({square, Side}) ->
    Side * Side;
%计算圆的面积,匹配circle  
area({circle, Radius}) ->
   % almost :-)
   3 * Radius * Radius;
%计算三角形的面积,利用海伦公式,匹配triangle 
area({triangle, A, B, C}) ->
   S = (A + B + C)/2,
math:sqrt(S*(S-A)*(S-B)*(S-C));
%其他
area(Other) ->
   {invalid_object, Other}.

执行一下看看:

1> c(mathStuff).
{ok,mathStuff}
2> mathStuff:area({square,2}).
4
3> mathStuff:area({circle,2}).
12
4> mathStuff:area({triangle,2,3,4}).
2.90474
5> mathStuff:area({other,2,3,4}).
{invalid_object,{other,2,3,4}}

Erlang使用%开始单行注释。

文章转自庄周梦蝶  ,原文发布时间5.17

时间: 2024-07-31 15:09:19

Erlang入门(一)的相关文章

Erlang入门(五)——补遗

时搞不到<Programming Erlang>,最近就一直在看Erlang自带的例子和Reference Manual.基础语法方面有一些过去遗漏或者没有注意的,断断续续仅记于此. 1.Erlang的保留字有: after and andalso band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse query receive rem try when xor 基本都是些用于逻

Erlang入门(三)——分布式编程

  明天要回家一个星期了,好好休息下.今天找到别人翻译的Erlang编程手册,值的好好读一遍.     所谓分布式的Erlang应用是运行在一系列Erlang节点组成的网络之上.这样的系统的性质与单一节点上的Erlang系统并没有什么不同.分布式这是个"大词",Erlang从语言原生角度支持分布式编程,相比于java简单不少. 一.分布式机制 下列的BIFs是用于分布式编程:spawn(Node, Mod, Func, Args) 启动远程节点的一个进程 spawn_link(Node

Erlang入门(二)—并发编程

Erlang中的process--进程是轻量级的,并且进程间无共享.查了很多资料,似乎没人说清楚轻量级进程算是什么概念,继续查找中...闲话不提,进入并发编程的世界.本文算是学习笔记,也可以说是<Concurrent Programming in ERLANG>第五张的简略翻译. 1.进程的创建     进程是一种自包含的.分隔的计算单元,并与其他进程并发运行在系统中,在进程间并没有一个继承体系,当然,应用开发者可以设计这样一个继承体系.     进程的创建使用如下语法: Pid = spaw

Erlang入门(四)——错误处理和鲁棒性

    去了趟福州,事情没搞定,托给同学帮忙处理了,回家休息了两天就来上班了.回家这几天最大的收获是第四次重读<深入Java虚拟机>,以前不大明了的章节豁然开朗,有种开窍的感觉,水到渠成,看来技术的学习还是急不来.     闲话不提,继续Erlang的学习,上次学习到分布式编程的章节,剩下三章分别是错误处理.构造健壮的系统和杂项,错误处理和构造健壮的系统今天一起读了,仅摘记下.     任何一门语言都有自己的错误处理机制,Erlang也不例外,语法错误编译器可以帮你指出,而逻辑错误和运行时错误

Erlang分布式在linux和windows上的注意事项

  没事做,就在两台机器间测试下Erlang分布式的例子,一个台是windowsXP,一台装的redHat9,没有详细的文档,自己摸索着搞成功了,记录下. 1.首先,分布式Erlang的实现提供了自有的安全机制来预防未经授权的Erlang系统访问.Erlang系统与别的机器进行交互时必须有同样的magic cookie,保存在一个称为.erlang.cookie的文件中,为了在两台不同机器间测试,需要编辑一份.erlang.cookie,内容随便,比如: just_test 然后将这份文件拷贝到

Docker技术入门与实战(第2版).

容器技术系列 Docker技术入门与实战 第2版 杨保华 戴王剑 曹亚仑 编著 图书在版编目(CIP)数据 Docker技术入门与实战 / 杨保华,戴王剑,曹亚仑编著. -2版. -北京:机械工业出版社,2017.1 (容器技术系列) ISBN 978-7-111-55582-7 I. D- II. ①杨- ②戴- ③曹- III. Linux操作系统-程序设计 IV. TP316.85 中国版本图书馆CIP数据核字(2016)第308604号 本书从Docker基本原理开始,深入浅出地讲解Do

20分钟 Awk 入门

20分钟 Awk 入门 什么是Awk Awk是一种小巧的编程语言及命令行工具.(其名称得自于它的创始人Alfred Aho.Peter Weinberger 和 Brian Kernighan姓氏的首个字母).它非常适合服务器上的日志处理,主要是因为Awk可以对文件进行操作,通常以可读文本构建行. 我说它适用于服务器是因为日志文件,转储文件(dump files),或者任意文本格式的服务器终止转储到磁盘都会变得很大,并且在每个服务器你都会拥有大量的这类文件.如果你经历过这样的情境--在没有像Sp

Erlang初学:Erlang的一些特点和个人理解总结_Erlang

我对 Erlang 编程理念的理解:以分布式架构师的角度写代码. 函数式编程 Erlang 里面的函数是数学里面的函数:必须有返回值. 只要是函数必然有返回值,函数是一个过程,以英文的句号为函数结束符. 函数结束之前的表达式就是该函数的返回值. 所以这也是在 Erlang 里面的函数不会看到任何 return 语句的原因. C++ 等其他语言的函数和函数之前可以通过共享变量来实现消息传递. Erlang 里面的函数不可以,消息的传递通过函数的传入和传出. 也只是为什么 Erlang 号称天生之处

Erlang和Golang的几点比较

问题描述 顺便说一下, 最早这篇文章发布在豆瓣上, 原作者是我. 我最早使用的语言是Java和Python, 并且一直都对Python充满好感, 我喜欢这种很朴实和高效率的感觉, 但我却最后没有采用Python,原因其实也很简单, 我就是不喜欢缩进语法, 就跟很多人换工作仅仅是为了屏幕更大一点一样, 另外就是有了同样很棒的可选方案, 这就是Ruby, 所以我最终采用了Ruby作为主力编程语言, 同样也为不能使用Python而有一点小遗憾,毕竟Python的健壮性比Ruby好很多,只不过Ruby也