Erlang for Python programmers: Part V

November 16, 2007

Previous parts: Intro, Part I, Part II, Part III and Part IV

List comprehensions.

List comprehensions is very familiar topic for Python programmer. It’s a syntactic sugar which provides a succinct notation for producing elements in list.

Erlang:

[Expr || Qualifier1,...,QualifierN]

Expr – is an arbitrary expression
Qualifier is either a generator or a filter.
A generator is of form Pattern <- ListExpr where ListExpr evaluates to a list of terms.
A filter expression should evaluate to true or false.

1> [X || X <- [1,2,3,4,5,6], X > 3].
[4,5,6]

This is read as: list of X such that X is taken from list [1,2,3,4,5,6] and X is greater than 3.

In foregoing example: X <- [1,2,3,4,5,6] is a generator and X > 3 is a filter.

Several filters can be combined:

2> [X || X <- [1,a,2,3,b,4,5,6], X > 3].
[a,b,4,5,6]
3> [X || X <- [1,a,2,3,b,4,5,6], integer(X), X > 3].
[4,5,6]

Generator part may act as a filter in list comprehension:

4> [X || {X, a} <- [{1, a}, {2, b}, {3, a}, erlang]].
[1,3]

Generators can be combined too in list comprehensions. This is the Cartesian product of two lists:

5> [{X, Y} || X <- [1, 2, 3], Y <- [a, b]].
[{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}]

This is how elegantly quicksort algorithm is solved with the help of list comprehensions in Erlang:

-module(sort).
-export([qsort/1]).

qsort([]) -> [];
qsort([Pivot|Tail]) ->
    qsort([X || X <- Tail, X < Pivot])
        ++ [Pivot] ++
        qsort([X || X <- Tail, X >= Pivot]).

Compile and run:

6> c("/home/alienoid/dev/erlang/sort", [{outdir, "/home/alienoid/dev/erlang/"}]).
{ok,sort}
7> sort:qsort([7, 5, 9, 3, 6]).
[3,5,6,7,9]

Usage of list comprehensions instead of some higher-order functions:

8> lists:map(fun(X) -> X*2 end, [1, 2, 3]).
[2,4,6]
9> [X*2 || X <- [1, 2, 3]].
[2,4,6]
10> lists:filter(fun(X) -> X rem 2 == 0 end, [1, 2, 3, 4]).
[2,4]
11> [X || X <- [1, 2, 3, 4], X rem 2 == 0].
[2,4]

Python:

[expression for expr1 in seq1 if cond1
            for expr2 in seq2 if cond2
            for exprN in seqN if condN]

this actually transforms to:

for expr1 in seq1:
    if not cond1:
        continue
    for expr2 in seq2:
        if not cond2:
            continue
        for exprN in seqN:
            if not condN:
                continue

So in Python Cartesian product of two lists [1, 2, 3 ] and ['a', 'b'] will look like:

>>> [(x, y) for x in [1, 2, 3] for y in ['a', 'b']]
[(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b')]

Variable bindings and scope rules in List Comprehensions:

Current Python 2.x “leaks” loop variable into surrounding scope. This should be solved in Python 3.0

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> vlist = [x for x in 'abc']
>>> vlist
['a', 'b', 'c']
>>> x
'c'

To avoid leaking loop variable into surrounding scope we can use generator expression which doesn’t “leak”:

>>> vlist = list(x for x in 'abc')
>>> vlist
['a', 'b', 'c']
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

Erlang has following scope rules for variables in list comprehensions(from Erlang manual):

  • all variables which occur in a generator pattern are assumed to be “fresh” variables
  • any variables which are defined before the list comprehension and which are used in filters have the values they had before the list comprehension
  • no variables may be exported from a list comprehension

So, Erlang doesn’t “leak” variables:

1> [X || X <- [1, 2, 3]].
[1,2,3]
2> X.
** 1: variable 'X' is unbound **

Be careful, sometimes you need to move some pattern matching operations into filter:

-module(listcomp).
-export([select/2]).

%% This select produces following warning during compilation:
%% Warning: variable 'X' shadowed in generate
select(X, List) ->
    [Y || {X, Y} <- List].

The function doesn’t produce desired result:

1> listcomp:select(b, [{b, 1}, {c, 2}, {b, 3}]).
[1,2,3]

So we modify generator and move pattern matching operation into filter to achieve what we need:

-module(listcomp).
-export([select/2]).

%% Moving X from pattern matching into filter
select(X, List) ->
    [Y || {X1, Y} <- List, X == X1].
2> listcomp:select(b, [{b, 1}, {c, 2}, {b, 3}]).
[1,3]

As you saw, while different in syntax, both languages provide valuable language construct which allows to write shorter and more elegant programs.


Delete blank lines with flush-lines

October 22, 2007

Sometimes after I copy-paste code snippets from web page into emacs buffer I get text with superfluous blank lines delimiting code.

Marking region and running M-x flush-lines RET ^$ RET quickly makes it better by removing those pesky blank lines. This is, of course, makes sense only if pasted code doesn’t contain blank lines you want to preserve.

Update:
You may need to use something more complex than simple ^$ (something like ^\W*$ as regexp) if “blank” line contains some whitespace characters.

Example before:

-export([test1/0,

         test2/0,

         test3/0,

         double/1]).

After marking region and applying M-x flush-lines RET ^\W*$ RET (in your case just ^$ may be sufficient):

-export([test1/0,
         test2/0,
         test3/0,
         double/1]).

Incremental search forward

October 5, 2007

Well-known incremental search forward(isearch-forward Lisp function) which is invoked with C-s has also additional useful key-bindings which I use often to instruct what to search. After you pressed C-s in buffer they are:

  1. C-w to yank next word or character in buffer onto the end of the search string, and search for it. You can repeatedly press C-w consuming next word or character.
  2. C-y to yank rest of line onto end of search string and search for it.
  3. M-n/M-p to search for the next/previous item in the search ring.

As usual for more information read help (C-h k C-s or C-h f isearch-forward RET ).


align-regexp

October 3, 2007

This interactive Emacs Lisp function was very handy for me during some log files analysis.

You mark region, invoke function, provide regexp and voila – your region is aligned.

Example data from align-regexp help:

Fred (123) 456-7890
Alice (123) 456-7890
Mary-Anne (123) 456-7890
Joe (123) 456-7890

Let’s say we want to align region on “(” character. For that we mark region we want to align and invoke function with: M-x align-regexp RET ( RET
Result of such invocation will be:

Fred      (123) 456-7890
Alice     (123) 456-7890
Mary-Anne (123) 456-7890
Joe       (123) 456-7890

Erlang for Python programmers: Part IV

October 2, 2007

Previous parts: Intro, Part I, Part II and Part III

Funs – sequel

Continuing previous post about functions let’s remember about Fun. I already mentioned it in Part I and promised to show its advanced forms. So, here we go.

Fun with one clause:

1> Double = fun(X) -> X * 2 end.
#Fun<erl_eval.6.56006484>
2> Double(2).
4

But Fun actually has the same function declaration syntax as regular function, except that it has no name in declaration, so we can have this:

3> Big = fun (X) when X > 100 -> true;
3>           (X) -> false
3>       end.
#Fun<erl_eval.6.56006484>
4> lists:filter(Big, [20, 30, 120, 130]).
[120,130]

As you see our Fun has two clauses separated by semicolon(;) and first clause has also guard, ie syntax is the same as in regular function declaration.

There are also following fun expressions that can be used:

  1. fun FunctionName/Arity (FunctionName should point to local function defined in the same module with our fun)
  2. fun Module:FunctionName/Arity (FunctionName should be exported from module Module)

fun FunctionName/Arity is just syntactic sugar for fun (X1, ..Xn) -> FunctionName(X1, .., Xn) end.

Let’s take a look on foregoing in action and create mymath.erl

-module(mymath).
-export([test1/0,
         test2/0,
         test3/0,
         double/1]).

test1() -> lists:map(fun(X) -> X * 2 end, [1, 2, 3]).

test2() -> lists:map(fun double_local/1, [1, 2, 3]).

test3() -> lists:map(fun mymath:double/1, [1, 2, 3]).

%% helper function, not exported
double_local(X) ->
    X * 2.

%% helper function, exported
double(X) ->
    X * 2.

Compile and test it (I’m compiling as usual in Emacs with C-c C-k):

1> c("/home/alienoid/dev/erlang/mymath", [{outdir, "/home/alienoid/dev/erlang/"}]).
{ok,mymath}
2> mymath:test1().
[2,4,6]
3> mymath:test2().
[2,4,6]
4> mymath:test3().
[2,4,6]

Also tuple of type {Module, FunctionName} is interpreted as a fun Module:FunctionName/Arity which you already saw. This usage is deprecated, but to be complete here is an example:

5> Append = {lists, append}.
{lists,append}
6> Append([1, 2], [3, 4, 5]).
[1,2,3,4,5]

As you already noted Fun in Erlang is “richer” than lambda in Python.

Built-in functions, BIFs

Both Erlang and Python provide built-in functions that are always available and do not require explicit usage of module name to use them.

Python:

Read more about builtins in library reference.

In Python shell you can inspect in addition contents of __builtins__ module if you need:

>>> import pprint
>>> pprint.pprint(dir(__builtins__))
['ArithmeticError',
 'AssertionError',
 ...
 'type',
 'unichr',
 'unicode',
 'vars',
 'xrange',
 'zip']

Erlang:
Most of the built-in functions belong to module erlang and they are auto-imported.
To get list of all BIFs with description read man erlang.
In Eshell you can get list of functions that belong to erlang module with m(Module). command:

1> m(erlang).
Module erlang compiled: No compile time info available
Compiler options:  []
Object file: preloaded
Exports:
'!'/2                         list_to_existing_atom/1
'$erase'/1                    list_to_float/1
'$erase'/0                    list_to_integer/2
'$get'/1                      list_to_integer/1
'$get'/0                      list_to_pid/1
'$get_keys'/1                 list_to_tuple/1
'$put'/2                      load_module/2
'*'/2                         loaded/0
'+'/1                         localtime/0
'+'/2                         localtime_to_universaltime/1
'++'/2                        localtime_to_universaltime/2
...
ok

Take into account though that not all functions in above list that you’ll see are auto-imported and may require usage of module: prefix. Again, for more information read man erlang (either in command line with erl -man erlang or if you use Emacs take a look at Erlang man pages in Emacs)

Macros

Python does not have them, Erlang does. In Erlang they are not as powerful as in Common Lisp, but more like in C.

They are defined in following form:

-define(Const, Replacement).
-define(Func(Var1,...,VarN), Replacement).

Whenever erlang preprocessor encounters expression of form ?MacroName it expands corresponding macro.
Define utils.erl:

-module(utils).
-export([foo/0]).
-define(TIMEOUT, 100).
-define(FUNCMACRO(X, Y), {X, x, Y, y}).

foo() ->
    io:format("TIMEOUT = ~p~n", [?TIMEOUT]),
    ?FUNCMACRO(3, 7).

Compile and run:

1> utils:foo().
TIMEOUT = 100
{3,x,7,y}

There are also some predefined macros:

?MODULE
The name of the current module.
?MODULE_STRING.
The name of the current module as a string.
?FILE.
The file name of the current module.
?LINE.
The current line number.
?MACHINE.
The machine name, 'BEAM'.

Having ?MODULE we can rewrite earlier example with Fun as:

-module(mymath).
-export([test1/0,
         test2/0,
         test3/0,
         double/1]).

test1() -> lists:map(fun(X) -> X * 2 end, [1, 2, 3]).

test2() -> lists:map(fun double_local/1, [1, 2, 3]).

%% test3() -> lists:map(fun mymath:double/1, [1, 2, 3]).
test3() -> lists:map(fun ?MODULE:double/1, [1, 2, 3]).

%% helper function, not exported
double_local(X) ->
    X * 2.

%% helper function, exported
double(X) ->
    X * 2.

And as usual compile and run to see that result is the same:

1> c("/home/alienoid/dev/erlang/mymath", [{outdir, "/home/alienoid/dev/erlang/"}]).
{ok,mymath}
2>  mymath:test1().
[2,4,6]
3>  mymath:test2().
[2,4,6]
4>  mymath:test3().
[2,4,6]

In addition there is also flow control in macros. Some of corresponding macro directives are:

  • ifdef(Macro). – Evaluate the following lines only if Macro is defined.
  • else. – It’s used after ifdef or ifndef
  • endif. - Marks the end of ifdef or ifndef directive

Example in utils.erl:

-module(utils).
-export([foo/0]).

-ifdef(debug).
-define(LOG(Msg), io:format("{~p:~p}: ~p~n", [?MODULE, ?LINE, Msg])).
-else.
-define(LOG(Msg), true).
-endif.

foo() ->
    ?LOG("Debug is enabled").

To turn LOG macro on debug should be defined. This can be achieved from command line with erlc -Ddebug utils.erl or from Eshell using c/2 function:

1> c(utils, {d, debug}).
{ok,utils}
2> utils:foo().
{utils:11}: "Debug is enabled"
ok

To turn LOG macro off debug should be omitted:

3> c(utils).
{ok,utils}
4> utils:foo().
true

To be continued.


Creating tables in Emacs

October 1, 2007

Sometimes I need to create tables in Emacs as it was in post describing comparison and arithmetic operations in Python and Erlang.

Over time I became aware of several means to create tables and export them in different formats in Emacs(at the moment I’m personally interested in plain ASCII and HTML):

  1. Excellent org-mode has built-in table editor which allows easily format tables in plain ASCII
  2. table.el with its advanced ability to construct table layout

Both modes (technically though Table mode in table.el is not mode) are part of modern Emacs and both allow export table in HTML format.

To quickly create tables personally I prefer table.el which provides also following features:

  1. A cell can be split horizontally and vertically.
  2. A cell can span into an adjacent cell.

Use C-h b in table to get self-descriptive information about table.el key bindings. In contrast to org-mode(or its orgtbl-mode minor mode) table.el has no special bindings to copy row/cell and yank it. But this is easily achieved by using usual region commands for rows and rectangular commands for cells.


Erlang for Python programmers: Part III

September 24, 2007

Previous parts: Intro, Part I and Part II

Today we are going to take a look at functions.
In Erlang there is no direct correspondence to what we have in Python:

1. default values, keyword arguments and formal parameter of form **name

def foo(key, name='ruslan', type='unknown', **kw):
    print 'key = %s, name = %s, type = %s' % (key, name, type)
    for key, val in kw.items():
        print '%s = %s' % (key, val)
>>> foo(1)
key = 1, name = ruslan, type = unknown
>>> foo(1, type='known', x=1, y=10)
key = 1, name = ruslan, type = known
y = 10
x = 1

2. formal parameter of form *name

def double_sum(*args):
    return sum(x * 2 for x in args)
>>> double_sum(2, 4, 5)
22

Let’s take a look at Erlang’s function declaration syntax (a bit modified from Erlang Reference Manual):

  1. Function declaration consists of function clauses separated by semicolons (;) and terminated by period (.)
  2. Function clause consists of head and body separated by ->
  3. A clause head consists of function name (which is atom), argument list(each argument is pattern) and optional guard sequence beginning with keyword when.
  4. A clause body consists of sequence of expressions separated by comma (,)

Name(Pattern11,…,Pattern1N) [when GuardSeq1] ->
Body1;
…;
Name(PatternK1,…,PatternKN) [when GuardSeqK] ->
BodyK.

where Body is in form:
Expr1,
Expr2,

ExprN

Number of arguments in function is called arity. Function is uniquely identified by combination of module name, function name and function’s arity and this form is often written as m:f/N. Two functions in the module with the same name, but different arity
are completely different functions, remember it.

Enough dry theory, let’s define our Erlang factorial function in module mymath.erl :

-module(mymath).
-export([factorial/1]).

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

What we have here:

1) function declaration of one function called factorial
2) there are two clauses
- first clause separated by semicolon (;)

factorial(0) ->
    1;

- second and final clause terminated with period (.)

factorial(N) ->
    N * factorial(N-1).

3) Every clause (first and second) has correspondingly head and body. Head consists of function’s name, in our case it’s factorial and after follows arguments list which contains patterns. In first clause pattern is 0, in second – N.

How this works:

When function is entered, the function clauses are pattern matched against passed arguments. Pattern matching happens in order functions are defined in module. So when you enter

1> mymath:factorial(5).
120

first 5 is matched against clause factorial(0) and fails as 5 != 0, then 5 is matched against N in second clause and pattern matching succeeds. As a result unbound variable N in pattern becomes bound and gets value 5. This leads to execution of body of second clause, namely N * factorial(N-1). This happens recursively until N becomes 0 and first clause factorial(0) is executed terminating recursion.
The same factorial function will look in Python without pattern matching like:

def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n-1)

In Python’s version we “hardcoded” branching in function’s body.

The benefits of pattern matching are that when conditions inside function become complex you may do your job better and write less code using pattern matching and also if you have big function this may mean that you do not have to modify body of your function but to add another clause with corresponding pattern.

Earlier I mentioned that function clauses are pattern matched in order they are defined in module. For our function this is important. If we change order of clauses this will lead to problems, as the condition to terminate recursion never appear:

-module(mymath).
-export([factorial/1]).

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

When compiling we will get warning (use C-c C-k in Emacs or c(mymath). in Eshell to compile)

2> c("/home/alienoid/dev/erlang/mymath", [{outdir, "/home/alienoid/dev/erlang/"}]).
/home/alienoid/dev/erlang/mymath.erl:6: Warning: this clause cannot match because a previous clause at line 4 always matches
{ok,mymath}

indicating that second clause will never match, but still you can call the function (it will most likely to crash after eating all your available memory).

You can easily avoid that problem introducing guard that starts with keyword when in function clause’s head:

-module(mymath).
-export([factorial/1]).

factorial(N) when N > 0 ->
    N * factorial(N-1);
factorial(0) ->
    1.

Now you can put those two clauses in any order you like. I should also add that if during pattern matching no matched function clause is found a function_clause run time error will occur:

3> mymath:factorial(-4).

=ERROR REPORT==== 24-Sep-2007::01:53:25 ===
Error in process <0.29.0> with exit value: {function_clause,[{mymath,factorial,[-4]},{erl_eval,do_apply,5},{shell,exprs,6},{shell,eval_loop,3}]}

** exited: {function_clause,[{mymath,factorial,[-4]},
                             {erl_eval,do_apply,5},
                             {shell,exprs,6},
                             {shell,eval_loop,3}]} **

What is guard anyway ? Guards make pattern matching more powerful, they can be used to perform different tests and comparison operations on variables in a pattern as you could see. You can have several guard expressions in clause separated by commans (,). The guard containing several guard expressions evaluates to true only if every guard expression evaluates to true. Example of guard containing several guard expressions:

-module(mymath).
-export([factorial/1]).

factorial(N) when is_integer(N), N > 0 ->
    N * factorial(N-1);
factorial(0) ->
    1.

For above definition calling mymath:factorial(5) reads as: choose clause factorial(N) when (N is integer AND N > 0)

There are also guard sequences which have form guard1; guard2; …; guardN and guard sequence evaluates to true if at least one guard is evaluated to true:

-module(mymath).
-export([factorial/1]).

factorial(N) when is_integer(N), N > 0; is_list(N) ->
    N * factorial(N-1);
factorial(0) ->
    1.

For above definition calling mymath:factorial(5) reads as: choose clause factorial(N) when (N is integer AND N > 0) OR N is list.

You have probably noted that the way we defined our factorial function means that it will be calling itself recursively and this will use stack and stack is not infinite resource. We need to do something about our function and this means to make it tail recursive. When last expression in function body is function call this means that call is tail recursive and this is how infinite loop may be done without consuming stack resources. So here is our new tail-recursive function factorial that uses accumulator to pass value of previous calculation:

-module(mymath).
-export([factorial/1]).

%% this one is exported, arity is 1
factorial(N) ->
    factorial(N, 1).

%% helper function, not exported, arity is 2
%% tail-recursive, uses accumulator to store
%% calculation between invocations
factorial(N, Acc) when N > 0 ->
    factorial(N-1, N*Acc);
factorial(0, Acc) ->
    Acc.

In foregoing example you can see guards, tail-recursion, usage of accumulators, functions with different arities. Experiment with it.


comment-dwim and comment-style

September 20, 2007

In my previous post I mentioned that if you use Emacs and you’re editing Erlang source code you can easily comment whole marked region by invoking M-; to which by default bound interactive Lisp function comment-dwim. This works in different modes and it’s very handy especially if your language of choice has no multiline comments.

So far so good, but I must admit sometimes I get the blues when I comment some nested code blocks with M-; keystrokes. Well, maybe I’m blowing things out of proportion about my sadness, but in any case recently I came across really nice small blog post called comment-style and since then I’m happy with comments produced in nested blocks. Let’s see why.

When you comment marked regions in Emacs buffer with M-; the comment-style variable defines the way regions are commented. Default value is plain.

Buffer with Python code before commenting:

def binsearch(seq, key, start, end):
    if end < start:
        return -1
    mid = (start + end) / 2
    if key == seq[mid]:
        return mid
    if key < seq[mid]:
        return binsearch(seq, key, start, mid-1)
    if key > seq[mid]:
        return binsearch(seq, key, start+1, end)

Buffer with Python code after commenting:

def binsearch(seq, key, start, end):
    if end < start:
        return -1
    mid = (start + end) / 2
    # if key == seq[mid]:
#         return mid
    if key < seq[mid]:
        return binsearch(seq, key, start, mid-1)
    if key > seq[mid]:
        return binsearch(seq, key, start+1, end)

As you see visually elements of commented block are not on the same line.

Example with Erlang code before commenting (somewhat far-fetched example though our main concern are comments, not code here):

all(Pred, [Hd|Tail]) ->
    case Pred(Hd) of
        true -> all(Pred, Tail);
        false ->
            io:format("Hd = ~p~n", [Hd]),
            true,
            false
    end;
all(Pred, []) when is_function(Pred, 1) -> true.

After commenting:

all(Pred, [Hd|Tail]) ->
    case Pred(Hd) of
        true -> all(Pred, Tail);
        false ->
            %% io:format("Hd = ~p~n", [Hd]),
%%             true,
            false
    end;
all(Pred, []) when is_function(Pred, 1) -> true.

So the visual issue with comments is the same.

After reading foregoing blog post about comment-style I’ve added this line to my .emacs:

(setq comment-style 'indent)

Easy as pie and which means (taken from Emacs help): ” …`comment-start’ markers should not be put at the left margin but at the current indentation of the region to comment.”

After that addition foregoing commented block in Python mode will look like:

def binsearch(seq, key, start, end):
    if end < start:
        return -1
    mid = (start + end) / 2
    # if key == seq[mid]:
    #     return mid
    if key < seq[mid]:
        return binsearch(seq, key, start, mid-1)
    if key > seq[mid]:
        return binsearch(seq, key, start+1, end)

in Erlang mode:

all(Pred, [Hd|Tail]) ->
    case Pred(Hd) of
        true -> all(Pred, Tail);
        false ->
            %% io:format("Hd = ~p~n", [Hd]),
            %% true,
            false
    end;
all(Pred, []) when is_function(Pred, 1) -> true.

Now I am happy. Thank you, Edward for the tip.


Erlang for Python programmers: Part II

September 16, 2007

In this short tutorial we will take a look at comparison operations, some arithmetic operations and modules. You may also want to skim over Inro and Part I.

Comparison operations

 Python   Erlang   Description             Erlang Example
 --------+--------+-----------------------+----------------
  <        <        strictly less than
 --------+--------+-----------------------+----------------
  <=       =<       less than or equal
 --------+--------+-----------------------+----------------
  >        >        strictly greater than
 --------+--------+-----------------------+----------------
  >=       >=       greater than or equal
 --------+--------+-----------------------+----------------
  !=       /=       not equal
 --------+--------+-----------------------+----------------
  ==       ==       equal                   1> 1 == 1.
                                            true
                                            2> 1 == 1.0.
                                            true
 --------+--------+-----------------------+----------------
           =:=      exactly equal to        1> 1 =:= 1.
                                            true
                                            2> 1 =:= 1.0.
                                            false
 --------+--------+-----------------------+----------------
           =/=      exactly not equal to
 --------+--------+-----------------------+----------------
  is                object identity
 --------+--------+-----------------------+----------------
  is not            negated obj identity

Python notes

Above comparison operations are supported by all objects. In Python you can chain comparisons:

>>> x, y, z = 1, 3, 7
>>> x < y <= z
True
>>> x < y and y <= z
True

Foregoing examples are identical, except that in second case y is evaluated twice.

Erlang notes

Following order is defined:

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

1> 5 < erlang.
true
2> erlang < make_ref().
true

Both Erlang comparison operators (<, =<, >, >=, /=, ==) and Python comparison operators(<, <=, >, >=, !=, ==) make type coerce, “narrower” type is widened to that of another, ie when comparing integer and float first integer is converted to float, etc.
Erlang has special operators without type coerce though: =:= and =/=

Arithmetic operations

I’ll provide only several operations, for more take a look at corresponding language references.

 Python   Python Desc.         Erlang    Erlang Desc.   Example
 --------+--------------------+---------+--------------+--------------------
  x % y    remainder            X rem Y   integer        >>> 7 % 3
           of x / y                       remainder      1
                                          of X / Y       >>> 7.0 % 3
                                                         1.0

                                                         1> 7 rem 3.
                                                         1
                                                         1> 7.0 rem 3.
                                                         =ERROR REP..
 --------+--------------------+---------+--------------+--------------------
  x / y    quotient             X / Y     floating       >>> 7 / 3
           of x and y                     point          2
                                          division       >>> 7.0 / 3
                                                         2.3333333333333335

                                                         1> 7 / 3.
                                                         2.33333
 --------+--------------------+---------+--------------+--------------------
  x // y   (floored) quotient   X div Y   integer        >>> 7 // 3
           of x and y,                    division       2
           integer division                              >>> 7.5 // 3
           (result type is                               2.0
           not forced to be
           int)                                          1> 7 div 3.
                                                         2

Modules

Code in Erlang is organized into units called modules, which is familiar word for Python programmer.

Let’s define sample module with function declaration stored in file mymath.erl :

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

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

What we see here:

  1. module’s source code is stored in file with .erl extension
  2. module consists of attributes and function declarations which are terminated by period (.)
  3. we should provide module declaration defining name of the module
  • module name should be atom
  • module name is the same as file name minus .erl extension
  • module declaration is mandatory
  • module declaration attribute should be defined first.

To make functions defined in module accessible outside the module we need to export them, for this -export module attribute exists. We write exported functions inside square brackets in form of func/N where N is the number of arguments of function, called arity. I’ll repeat that functions not pointed in -export will not be accessible outside module.

Before code can be run, module must be compiled. Resulting compiled file will contain extension .beam

If you use Emacs you can compile module with C-c C-k and see results in erlang shell:

1> c("/home/alienoid/dev/erlang/mymath", [{outdir, "/home/alienoid/dev/erlang/"}]).
{ok,mymath}

Or you can compile it directly in shell. Make sure your shell’s current directory is where your mymath.erl lives, if it’s not the case use cd command in erlang shell, cd(”/path/to/dir/with/mymath.erl”) :

1> c(mymath).
{ok,mymath}

To invoke our function fact we use syntax mod:func :

2> mymath:fact(4).
24

Erlang has also -import attribute which allows to import functions into modules, so that you don’t need to use fully-qualified name mod:func to invoke function, again familiar behaviour and naming to Python programmer.

Erlang allows to insert code from file as-is with -include attribute at point where -import is defined, this is used to include records and macro definitions, for example.

Comments in Erlang module begin with character “%“, continue up to end-of-line and may be placed anywhere except inside string and quoted atoms.
Like in Python Erlang has no multiline comments.
If you use Emacs you can easily comment whole region with M-; command after you marked it.

-module(mymath).
-export([fact/1, print_double/1]).
-import(lists, [foreach/2]).
-include("my_records.hrl").

%% sum(L) ->
%%     sum(L, 0).

%% sum([H|T], Acc) ->
%%     sum(T, H+Acc);
%% sum([], Acc) -> Acc.

fact(0) -> 1;
fact(N) -> N * fact(N-1).
print_double(L) ->
    foreach(fun(X) -> io:format("Double of ~p = ~p~n", [X, X*2]) end, L).

Fin.

Next tutorial will be devoted to thorough exploration of functions in Erlang.


How to say big numbers in English: Common Lisp

September 12, 2007

When i was describing notations and representation of numbers in Erlang(and Python) i forgot to mention very cool feature of format function in Common Lisp, with which i got acquainted exploring highly-recommended Practical Common Lisp book.

This feature is ~R directive which knows how to say really big numbers in English words.

Here is the example (I use SBCL + SLIME):

CL-USER> (format nil "~R" 1604872898756737459538)
"one sextillion six hundred four quintillion eight hundred seventy-two
quadrillion eight hundred ninety-eight trillion seven hundred fifty-six
billion seven hundred thirty-seven million four hundred fifty-nine
thousand five hundred thirty-eight"