Erlang学习之路

一:环境搭建:eclipse开发erlang


Erlang 的官方网站是http://www.erlang.org.其左侧的连接指出了我们可以从这里获取的资源。

Erlang学习之路_第1张图片

其中,

Downloads 连接可以下载到所有版本的Erlang.

Links 是一些其它资源的链接

Enhancements 是一些Erlang的增强功能

Getting Started 是教学

Documentation 文档,相当于帮助文件

Examples 示例

 

二、安装

以Windows下安装为例。下载最新 Windows binary 版本。如:R14B01。下载后文件名为 otp_win32_R14B01.exe 直接安装即可。安装后的路径设置,这步很重要!

方法一、

把bin (如 C:/erl5.8.2/bin)添加到系统变量的Path后(右键我的电脑/属性/高级/环境变量)。

方法二、

在环境变量里增加 EL_PATHS 值为 对应的 bin 路径。然后把 %EL_PATHS% 添加到 Path里。这种做法会在eclipse中使用erlang时自动在方法一的基础上完成。

三、检查Erlang是否安装成功

打开 cmd ,输入 erl 后回车,如果看到如下的信息,表明安装成功。

 

四、使用 eclipse

eclipse 开发 erlang 的要求

1、eclipse版本 3.5.0 至 3.5.2

2、jdk 1.5

3、erlide

Ok,先安装 jdk 1.5 ,运行解压后的 eclipse (最好是只含java的版本),然后在 Help / Install New Software 中使用 http://erlide.org/update 进行更新。在选项列表中选中

Erlang学习之路_第2张图片

就可以了。安装后重启eclipse。完成!

五、第一个 erlang Hello World!

1、打开 eclipse , New / Project / Erlang Project

Erlang学习之路_第3张图片

输入 Project Name “HelloWorld”,点击 Finish

eclipse 会自动创建三个文件夹

image

其中:

ebin 存放编译之后的二进制文件(扩展名为beam)

include 存放程序中所引用到的文件

src  存放源码文件

2、右击 src ,选 New Module 来新建一个erlang文件(其扩展名为erl)

在Module Name 输入“hw”。注意,这里的名称要小写的英文或下划线。点击 Finish

3、编写print函数

输入以下代码

printHelloWorld() -> 
    io:format("Hello World!~n").

OK,接下来把printHelloWorld写入到-export里,这样就可以把函数导出了。如:-export([printHelloWorld/0]).  这里的0表示没有参数。

说明:函数名称要求第一个字母小写,大写被示为变量。函数的一般格式为

方法名称(参数) –>

    方法体.(注意这里的结束符为一个英文件的句点)

3、编译

右击hw.erl,选择 Run As / Run Configurations…

双击 Erlang application 会产生一个新的配置

image

在右侧选择你的工程

在Runtimes下输入一个Node Name

之后点击 Apply,Run就可以运行了

这时在控制台 Console 里就会出现

Erlang学习之路_第4张图片

编译命令为 c(文件名).

我们输入c(hw).之后回车

Erlang学习之路_第5张图片

这时提示一个错误:没有对应的文件。

使用pwd().查看当前的路径为

可见,hw.erl所在目录src没有被识别。所以我们使用cd命令转到这个目录

之后就可以编译了

image

编译后在ebin目录下会产生相应的hw.beam文件。运行如下

OK,第一个HelloWorld程序完成了。


二:Erlang简明教程


    1. 介绍
    2. 几个简单例程
    3.  Basic Principle
    4.  并发编程
    5.  分布式
    6.  错误处理
    7.  程序的健壮性
    8.  附录(一些来自网络的小资料)

1. 介绍
    Erlang是一门函数式语言。
    Erlang是一个丹麦的数学家,他搞出来的一个概率分布Erlan分布,并且用这个分布开创一们学
科排队理论,电信上经常用这个分布来测算话务量,因此在电信界比较有名.当年Joe Amstrong把他
的语言命名为Erlang也是为了纪念这个为电信领域作出过卓越贡献的人.
    Erlang是Ericsson和Ellemtel Computer Scientce Laboratories为解决电信领域中的并发和
分布式问题,设计的语言;从理论应用于实践的角度讲,主要探索的是函数式语言能否应用到通信
领域的大型交换机上,从Erlang的实践效果来看,答案是肯定的。
    Erlang的优点:
    (1) Code Loading Primitives允许在系统运行过程中升级代码。
    (2) Erlang的轻量级进程可以支持极高的并发性,而且在高并发的情况下内存使用相当的少。
        Erlang的并发性并不会受到宿主操作系统并发性的限制。Erlang的原子操
 作是一个压栈级别的,而C语言是指令级别的。
    (3) 最开始Erlang的设计目标就是实现分布式环境,一个Erlang的虚拟机就是一个Erlang网络上
        的节点。一个Erlang节点可以在另一个-Erlang节点上创建自己的并发进程,而子进程所在的
        节点可能是运行其他的操作系统的服务器。不同节点的之间的可以进行极为高效而又精确的通
        信,就像它们运行-在同一个节点一样。
    (4) Erlang内部建设有多种错误检测原语。我们可以通过这些原语来架设高容错性的系统。例如,
        一个进程可以监视其他进程的状态和活动,即使那些被监-控的进程处于其他节点。在分布式状
        态下,我们可以把系统配置成具有Fail-over功能的分布式系统。当有其他节点出错的时候,系
        统会把他的运行场景自动快速-的切换备份节点上。
    (5) Erlang是一个“软”实时系统(Soft Real Time),它可以提供毫秒级别的响应。

2. 几个简单例程
   2.1 How to run?
       笔者用的是Win2000。
       首先安装otp_win32_R11B-2.exe。
       a. 建立Erlang程序(vi/Emacs/Notepad都可以的编辑器),文件名的格式是 *.erl。
          读者可以暂时先在下面的程序中,Copy一份来做运行试验。
       b. 进入终端,把路径定位到您的*.erl目录中
       c. 启动Erlang程序
          笔者的启动方式:"d:/Program Files/erl5.5.2/bin/erl.exe"
          读者可以根据自己的路径,启动程序。
       d. 编译程序
          c(math.erl).
          或者 c(math).
          注意:结尾的.是不能省略的
       e. 运行
          math:fib(10).
       f. Erlang的帮助
          help().
   2.2 简单例程
       2.2.1 阶乘
     -module(math).  %定义模块名字
     %也可以理解成为一个起到命名空间
     %的作用
            -export([fact/1]).  %起到了头文件(*.h)的作用
     %声明这个函数,供外部调用
            fact(0) -> 1;              
            fact(N) -> N * fact(N-1).
           
            这是一个算阶乘的程序。
            % -- 注释符号
            具体执行 fact(0)还是fact(N),Erlang是模式匹配的,当前的N匹配
        上哪个定义,就执行哪一个。
            /1 -- 说明这个函数接受一个参数。
            -> -- 定义函数的方式,请类比数学当中的映射。
      2.2.2 定义更多的函数
         
      -module(math).         
      -export([fact/1]).     
      -export([fib/1]).
      fact(0) -> 1;
             fact(N) -> N * fact(N-1).
             fib(1) -> 1;
             fib(2) -> 2;
             fib(X) -> fib(X-1) + fib(X-2).
 
           也可以这样:
      -module(math).         
      -export([fact/1, fib/1]).
           
               ...  ...
           如果你要定义成这个样子:
              -module(math).         
       -export([fact/1]).     
       fact(0) -> 1;
              fact(N) -> N * fact(N-1).
              fib(1) -> 1;
              fib(2) -> 2;
              fib(X) -> fib(X-1) + fib(X-2).
           那么fib(N)只能在math模块内部使用(fib是private的)。
           注:下面的程序为了简单,只是写实现。
       2.2.3 操作List
            
      reverse(L) -> reverse(L, []).   %1
      reverse([H|T], Acc) ->          %2
               reverse(T, [H|Acc]);      %3
      reverse([], Acc) ->             %4
               Acc.                          %5
            
      []是list的符号
             %1 使用了[],这起到了辅助量的作用。
             %2 [H|T] 这种形式代表取list的头和余下的部分
                      H绑定了list的头(Head)
                      T绑定了list的余下部分(Tail)
             %[] 空表
             %2 + %3 代表一个子句(clause),用';'来分隔子句
                   子句内部用','
                     标识结束用'.'
             你也许可以编个大段的程序,来体会何时用',' , ';' , '.'。
       2.2.4 匹配更多的函数
             -module(math3).
             -export([area/1]).
      area({square, Side}) ->
  Side * Side;
      area({rectangle, X, Y}) ->
  X * Y;
             area({circle, Radius}) ->
  3.14159 * Radius * Radius;
      area({triangle, A, B, C}) ->
  S = (A + B + C)/2,
  math:sqrt(S*(S-A)*(S-B)*(S-C)).
      这是一个计算基本图形面积的例程。
             S为一个临时量。
             可以通过math3:({triangle, 3, 4, 5})计算三角形
                 通过math3:({circle, 5})计算圆
 
       2.2.5 快速排序
             -module(sort).
      -export([sort/1]).
      sort([]) -> [];
       sort([Pivot|Rest]) ->
                {Smaller, Bigger} = split(Pivot, Rest),
                lists:append(sort(Smaller), [Pivot|sort(Bigger)]).
      split(Pivot, L) ->
                split(Pivot, L, [], []).
      split(Pivot, [], Smaller, Bigger) ->
                {Smaller, Bigger};
             split(Pivot, [H|T], Smaller, Bigger) when H < Pivot ->
  split(Pivot, T, [H|Smaller], Bigger);
             split(Pivot, [H|T], Smaller, Bigger) when H >= Pivot ->
  split(Pivot, T, Smaller, [H|Bigger]).
  
             这个排序大家很熟悉吧,在这里就不介绍这个算法的原理了。
             只是想就这个例程来发一些感慨。
             这个程序很简洁,实现即原理。
             入学从Lisp或其他函数式语言而不是C语言来教授计算机课程,
         个人感觉更能让学生专注在算法的理解上;如果,用C写这个程序,要考虑很
         多怎样交换的细节问题、变量定义等,尤其老师会说递归是个很耗资源
         的调用方式,很容易堆栈溢出,很多因素让学生分心了、对实现怀疑了。
             希望有能力改变一些东西的老师,去改变一些东西。
3. Basic Principle
 
  3.1 Tuples
      特点:确定数目的item。
      用于创建复杂的数据结构。
      符号是'{}'。
      请读者看一下2.2.4的例程,我们可以这样调用它。
 > Thing = {triangle, 6, 7, 8}.
 {triangle, 6, 7, 8}
 >math3:area(Thing).
 20.3332
      这里就把Thing绑定(bound)到了一个tuple上--{triangle, 6, 7, 8},请读者注意
   这里的用词:"绑定(bound)"。我们在Erlang中是没有变量的概念的,所有用到的量都是
   一次性赋值,即绑定。
      继续我们的Tuple...
      Thing是一个有4项的tuple。第一项是原子量triangle,剩下的三项是整型数6,7,8。
      其他例子:
      {a, 12, b}, {}, {1, 2, 3}, {a, b, c, d ,e}.
     
  
   3.2 List
       特点:存储不定数目的item。
       符号是'[]'
       例子:
       [], [a, b, 12], [22], [a, 'hello friend']

   3.3 补充Data Types
 3.2.1 Constant data types
            -Numbers: 123, -789, 3.14159, 7.8e12, -1.2e-45.
                      分为整数和浮点数。
            -Atoms: abc, 'An atom with spaces', monday,green,hello_world
 3.2.2 Compound data types(复合型)
            用于把不同类型的数据组织起来。
            -Tuples
            -Lists
    3.4 一个复杂的数据结构
        组合使用tuples 和 lists可以帮助我们创建复杂的数据结构。
    X = {book, preface, acknowledgments, contents,
   {chapters, [
      {chapter, 1, 'An Erlang Tutorial'},
      {chapter, 2, ...}
      ]
    }},
         用一个复杂的数据结构,把一本书表示了出来,美极了。
         :)
     3.5 Pattern matching
         
         处理匹配失败了怎么办?
           -module(temp).
    -export([convert/2]).
   
    convert({fahrenheit, Temp}, celsius) ->
  {celsius, 5 * (Temp - 32) / 9};
    convert({celsius, Temp}, fahrenheit) ->
  {farenheit, 32 + Temp * 9 / 5};
    convert({reaumur, Temp}, celsius) ->
  {celsius, 10 * Temp / 8};
    convert({celsius, Temp}, reaumur) ->
  {reaumur, 8 * Temp / 10};
    convert({X, _}, Y) ->  %匹配失败了
  {cannot,convert,X,to,Y}.        %处理匹配失败
        
  运行:
 > temp:convert({fahrenheit, 98.6}, celsius).
 {celsius,37.0000}
 > temp:convert({reaumur, 80}, celsius).
 {celsius,100.000}
 > temp:convert({reaumur, 80}, fahrenheit).
 {cannot,convert,reaumur,to,fahrenheit}
        程序中使用了一个下划线'_'来捕捉失败的情况,这个'_'的作用像是C中的default
     它表示:这里有一个值,但这个值具体是什么我不关心。
        注意这个东西一定要放到最好,这一点不像C中的default,Erlang有些地方不是很
     智能,这也许是基于电信中的效率考虑吧。设想热恋中,你鼓足勇气要说"I love you"
     之类的东西了,这时候,电信信息要升级、匹配什么的,总之是断了一下......这让你
     觉得有什么先兆,胡思乱想... ...“算了,不说了”....
        效率就是一切,把一切都交给程序员吧。
      3.6 '='
 > N = {12, banana}.
 {12,banana}
 > {A, B} = N.
 {12,banana}
 > A.
 12
 > B.
 banana
        看明白了吗?

4. 并发编程
 
 Erlang是并行语言。
        也就是说Erlang对并行的支持是语言级别的,不需要操作系统的支持。
        'spawn'启动一个过程(process),给一个process发消息,从一个process收消息。
        'spawn/3'启动一个process并返回一个标识(identifier),这个标识用于收、发
      消息。
        语法: Pid ! Msg
        Example: Pid ! {a, 12}
   Pid : identifier
            !  : 发消息标识
           {a, 12} : 一条消息
 所有参数在发消息之前都要计算(比较:Erlang中是懒惰求值的,但是在发消息的
      时候,必须提前计算)。
        Example: foo(12) ! math3:area({square, 5})
        计算foo(12) 和 math3:area({square, 5}),但是两边的计算规则是未定义的。
       〔
         这一段翻译的不好,原文:
  foo(12) ! math3:area({square, 5})
         means evaluate the function foo(12) (this must yield a valid process
         identifier) and evaluate math3:area({square, 5}) then send the result
         (i.e. 25) as a message to the process. The order of evaluation of the
          two sides of the send primitive is undefined.
         〕
         'receive'原语,用于收消息。
         语法:
  receive
      Message1 ->
   ... ;
      Message2 ->
   ... ;
   ...
  end
          含意:定义一组收消息的模式语意,用于在收到消息后,当消息匹配上一条
        MessageN,执行这个消息'->'后面的语句。
          如果收到的消息,没有匹配上receive...end中定义的模式,这个收消息的过
        程将挂起,等待处理下一条消息;未匹配的消息,将保存,等待后续处理。
   Example:
        {A, Msg}
  A --------------------------------->B
                         Msg
                A<----------------------------------B
     
                           An echo process
  -module(echo).
  -export([start/0, loop/0]).
  
  start() ->
   spawn(echo, loop, []).
  loop() ->
   receive
      {From, Message} ->
       From ! Message,
       loop()
   end.
   运行:
  Id = echo:start(),
  Id ! {self(), hello}.
          self()是个内建函数(BIF),返回该过程的identifier


你可能感兴趣的:(Erlang学习之路)