利用者:Ansimionescu/Notes/7

提供: wiki
移動先: 案内検索

Erlang basics

Erlang is a functional programming language based on a runtime environment which is the basis for program execution. This makes it easily portable - you only have to port the ERTS. For full or short reference/guides, check [1] or [2]. Check out the history/philosophy behind Erlang on Wikipedia [3].

OTP [4-6] is set of Erlang libraries and design principles providing middle-ware to develop these systems. It includes its own distributed database, applications to interface towards other languages, debugging and release handling tools.

Erlang-overview.jpg

Types

Simple

  • integers
  • characters: implemented like special integers
$A % this is 65
  • float
  • bignums: long ints
  • atoms
    • name starts with lower-case
    • can be compared to a constant
    • value(an atom) == the atom itself
  • variables
    • name starts with upper-case
    • can't change the value once you set it
  • references
  • PIDs
  • ports

Structures

  • tuples
    • symbol: { }
    • containers of fixed number of terms
    • can contain other tuples
    • equivalent of a vector
  • lists
    • symbol: []
    • container of a variable number of terms
    • equivalent of a linked list
    • can contain other tuples/lists
  • binaries
    • blobs of memory
    • term <-> binary

Constructing data

Erlang is dynamically typed. You can't declare a type, the system keeps track of this for you.

Appending an element to a list L:

[element | L]

Removing an element from L:

[A | L] = [1, 2, 3]

Erlang is built on pattern matching, which basically means assigning values to make the '=' statements true.

Functions

  • must be declared
-export([<name>/<n-of-args>]).
  • have a head (name, args, optional condition) and a body (sequence of expressions separated by comma)
Name(Pattern11,...,Pattern1N) [when GuardSeq1] ->
    Body1;
...;
Name(PatternK1,...,PatternKN) [when GuardSeqK] ->
    BodyK.
  • built-in functions (see more examples below): implemented in C code, usually impossible or too difficult to implement in erlang
1> tuple_size({a,b,c}).
3
2> atom_to_list('Erlang').
"Erlang"

Guards

A way to implement conditional statements. Example of guards:

  • == equality
  • =/= non equality
  • list(L) checks if L is a list
  • tuple(Tup)
  • binary(Bin)
  • pid(Pid)
  • port(Port)
  • length(List)
  • relational operators
atomorint(Atom) when atom(Atom) -> true;
atomorint(Int) when integer(Int) -> true;
atomorint(_Other) -> false.

Control structures

%%% The case statement
foo() -> case bar(X) of
   {case1, Arg}    -> handle_it(Arg);
   {case2, Value}  -> handle2(Value);
   Anything        -> true            % Works as 'default'
end.

%%% If statement
foo(X) -> if
   X == 2   -> foo1();
   X == 3   -> foo2();
   true     -> true                   % Works as 'else'
end.

Concurrent Erlang

Erlang has extremely lightweight processes, since it's build for massive concurrency.

Creating processes

spawn(Module, Name, Args) -> pid()
  Module = Name = atom()
  Args = [Arg1,...,ArgN]
    ArgI = term()

spawn creates a new process and returns the pid.

The new process will start executing in Module:Name(Arg1,..,ArgN) where N can be 0.

You can register a process by assigning its pid to a name.

register(Name, Pid) % Associates the name Name, an atom, with the process Pid.
registered()        % Returns a list of names which have been 
                    % registered using register/2.
whereis(Name)       % Returns the pid registered under Name, or
                    % undefined if the name is not registered.

Terminating processes

When a process terminates, it always terminates with an exit reason. The reason may be any term.

A process is said to terminate normally, if the exit reason is the atom normal. A process with no more code to execute terminates normally.

A process terminates with exit reason {Reason,Stack} when a run-time error occurs.

A process can terminate itself by calling one of the BIFs:

  • exit(Reason)
  • erlang:error(Reason)
  • erlang:error(Reason, Args)
  • erlang:fault(Reason)
  • erlang:fault(Reason, Args)

The process then terminates with reason Reason for exit/1 or {Reason,Stack} for the others.

Message sending

Erlang-processes-comm.gif
%%% Send
Expr1 ! Expr2

Sends the value of Expr2 as a message to the process specified by Expr1. The value of Expr2 is also the return value of the expression.

Expr1 must evaluate to a pid, a registered name (atom) or a tuple {Name,Node}, where Name is an atom and Node a node name, also an atom.

  • If Expr1 evaluates to a name, but this name is not registered, a badarg run-time error will occur.
  • Sending a message to a pid never fails, even if the pid identifies a non-existing process.
  • Distributed message sending, that is if Expr1 evaluates to a tuple {Name,Node} (or a pid located at another node), also never fails.
%%% Receive
receive
    Pattern1 [when GuardSeq1] ->
        Body1;
    ...;
    PatternN [when GuardSeqN] ->
        BodyN
end

Receives messages sent to the process using the send operator (!). The patterns Pattern are sequentially matched against the first message in time order in the mailbox, then the second, and so on. If a match succeeds and the optional guard sequence GuardSeq is true, the corresponding Body is evaluated. The matching message is consumed, that is removed from the mailbox, while any other messages in the mailbox remain unchanged.

The return value of Body is the return value of the receive expression.

receive never fails. Execution is suspended, possibly indefinitely, until a message arrives that does match one of the patterns and with a true guard sequence.

%%% Receive example
wait_for_onhook() ->
    receive
        onhook ->
            disconnect(),
            idle();
        {connect, B} ->
            B ! {busy, self()},
            wait_for_onhook()
    end.

%%% Receive with timeout example
wait_for_onhook() ->
    receive
        onhook ->
            disconnect(),
            idle();
        {connect, B} ->
            B ! {busy, self()},
            wait_for_onhook()
    after
        60000 ->
            disconnect(),
            error()
    end.

Coding

How to write and run a ".erl"

  • write your code in module.erl
  • launch 'erl' in console
  • compile your module using c(module). or c(module.erl).
  • now you can use what you declared with '-export([..]).'
  • do it by appending the module name before; e.g. 'module:foo(1).'
example.erl

-module(example).
-export([fact/1]).

fact(0) -> 1;
fact(N) -> N * fact(N-1).

Eshell V5.5.5  (abort with ^G)
1> c(example).
{ok,example}
2> example:fact(0).
1
3> example:fact(5).
120
4> example:fact(10).
3628800
5> example:fact(25).
15511210043330985984000000

Built in functions examples

%%% Can be used as guards:
75> trunc(5.6).
5
76> round(5.6).
6
77> length([a,b,c,d]).
4
78> float(5).
5.0
79> is_atom(hello).
true
80> is_atom("hello").
false
81> is_tuple({paris, {c, 30}}).
true
82> is_tuple([paris, {c, 30}]).
false

%%% Can't be used in guards:
83> atom_to_list(hello).
"hello"
84> list_to_atom("goodbye").
goodbye
85> integer_to_list(22).
"22"

Simple RPC server-client example

%%% Server
% Assume the server is registered under the name 'rex'
loop() ->
   receive
      {From, {apply, M, F, A}} ->
         From ! {rex, node(), apply(M, F, A)}
         loop();
      _Other ->
         loop();
   end.

%%% Client
call(Node, M, F, A) ->
   {rex, Node} ! {self(), {apply, M, F, A}},
   receive
      {rex, Node, What} ->
         What
   end.

Home:

[0] http://wiki.blender.org/index.php/User:Ansimionescu

Reference:

[1] Short http://www.erlang.org/doc/getting_started/users_guide.html

[2] Full http://www.erlang.org/doc/reference_manual/users_guide.html

[3] Wikipedia http://en.wikipedia.org/wiki/Erlang_(programming_language)#History

[4] Open Telecom Platform https://github.com/erlang/otp

[5] OTP #2 http://learnyousomeerlang.com/what-is-otp

[6] OTP #3 https://github.com/erlang/otp/blob/maint/README.md