博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Erlang入门(一)
阅读量:6477 次
发布时间:2019-06-23

本文共 5218 字,大约阅读时间需要 17 分钟。

  读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的控制的流转是通过模式匹配来实现的。具体功能参见链接,给出书中拆解列表的例子:
    [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;
dot.gif
PatternN [when GuardN] 
->
 SeqN
end
if和case语句都有一个问题,就是当没有模式匹配或者Grard都是false的时候会导致error,这个问题case可以增加一个类似java中default的:
case Fn of
dot.gif
   _ 
->
   true
end
通过_指代任意的Expr,返回true,而if可以这样:
if
  
dot.gif
  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

转载地址:http://wsqko.baihongyu.com/

你可能感兴趣的文章
程序员的视角:java 线程(转)
查看>>
VisualSVN
查看>>
自定义Section
查看>>
在.NET开发中的单元测试工具之(2)——xUnit.Net
查看>>
Go之类型判断
查看>>
第二百五十二节,Bootstrap项目实战-首页
查看>>
Gray Code
查看>>
python 依照list中的dic的某key排序
查看>>
机器学习--详解人脸对齐算法SDM-LBF
查看>>
js中几种实用的跨域方法原理详解
查看>>
Go语言的基准测试简单示例
查看>>
PLSQL连接Oracle 数据库配置详解
查看>>
load函数
查看>>
gsp页面标签
查看>>
慎用Outline ,UGUI Outline实现原理分析
查看>>
权限表的设计
查看>>
Effective C++:规定24:如果所有的单位都需要的参数类型转换,使用请做到这一点non-member功能...
查看>>
iOS经典面试题(转)
查看>>
DELPHI 数学函数+字符处理函数
查看>>
分享几个.NET WinForm开源组件,纪念逐渐远去的WinForm。。。
查看>>