Related Posts

 

if-else

In F#, if-else if-else con­trol flow is expressed in the form if Exp then Exp elif Exp then Exp else Exp:

let f n =

    if n = 42 then

        printfn “%d is the answer to the ulti­mate ques­tion of life, the uni­verse and every­thing” n

    elif n % 2 = 0 then

        printfn “%d is even” n

    else

        printfn “%d is odd” n

In Erlang, there’s not explicit else if or else clauses, instead you just spec­ify mul­ti­ple clauses and the last catch-all (true –> …) is Erlang’s equiv­a­lent of the ‘else’ clause.

f (N) –>

    if N =:= 42 -> io:format(“~p is the answer to the ulti­mate ques­tion of life, the uni­verse and every­thing”, [N]);

       N rem 2 =:= 0 -> io:format(“~p is even”, [N]);

       true -> io:format(“~p is odd”, [N])  % this is Erlang’s equiv­a­lent to an ‘else’

    end.

When you’re writ­ing Erlang you’re usu­ally dis­cour­aged from using ‘else’ or ‘true’ branches alto­gether and should instead replace them with if clauses that cover all log­i­cal branches to help avoid mask­ing oth­er­wise hard-to-detect bugs.

 

match-with

The pre­ferred way (for me at least) to do con­di­tional branch­ing in F# is to use the match-with expres­sion rather than using ifs. The logic expressed in the func­tion f from the above exam­ple can eas­ily be expressed in a match-with instead:

let g n =

    match n with

    | 42 -> printfn “%d is the answer to the ulti­mate ques­tion of life, the uni­verse and every­thing” n

    | _ when n % 2 = 0 -> printfn “%d is even” n

    | _ -> printfn “%d is odd” n

Erlang’s coun­ter­part to match-with is the case-of expres­sion, which looks a lot like match-with:

g (N) –>

    case N of

        42 -> io:format(“~p is the answer to the ulti­mate ques­tion of life, the uni­verse and every­thing”, [N]);

        _ when N rem 2 =:= 0 -> io:format(“~p is even”, [N]);

        _ -> io:format(“~p is odd”, [N])

    end.

 

Type Con­ver­sions

In F#, you can cast a value of type T into a value of type V like this:

let n = int “42”

pro­vided that there exists an explicit cast oper­a­tor that lets you con­vert a value of type T to type V.

In Erlang, type con­ver­sion is achieved with the help of built-in func­tions that are gen­er­ally named T_to_V where T and V are the names of the source and des­ti­na­tion types:

N = list_to_integer(“42”).

There are many other such built-in func­tions, includ­ing: atom_to_binary, atom_to_list, binary_to_atom, list_to_atom, integer_to_list, …

From the above exam­ple, you might be won­der­ing why the built-in func­tion that con­verts a string to an inte­ger is called list_to_integer as opposed to string_to_integer. This is because there is no real string type in Erlang!

In Erlang, strings are lists of inte­gers whose ele­ments are all inte­gers that rep­re­sent print­able characters:

1> [52, 50].

“42”

2> % 2 is not a print­able char­ac­ter, so this is treated as an inte­ger list

2> [52, 50, 2].

[52, 50, 2]

3> [ 104, 101, 108, 108, 111 ].

“hello”

4> % you can use the $ oper­a­tor to find out the inte­ger value of a character

4> $/.

47

5> $n.

110

I’m sure many a devel­oper has enjoyed a won­der­ful WTF moment when they realised the lack of a native string type in Erlang, but given its ori­gin in the tele­com world where string manip­u­la­tion is sel­dom required it’s per­haps not sur­pris­ing that the lan­guage design­ers never saw fit to make string manip­u­la­tion more natural.

But seri­ously, WTF!

 

Type Tests

Type test­ing is per­formed with the : ? oper­a­tor in F#:

let f (n : obj) =

    match n with

    | : ? int as nInt -> printfn “%d is an inte­ger” nInt

    | : ? float as nFloat -> printfn “%f is a float” nFloat

    | : ? string as nStr -> printfn “%s is a string” nStr

In Erlang, you can use a num­ber of built-in func­tions named is_T where T is the name of the type:

f (N) –>

    case N of

        _ when is_integer(N) -> io:format(“~p is an inte­ger”, [N]);

        _ when is_float(N) -> io:format(“~p is a float”, [N]);

        _ when is_list(N) -> io:format(“~p is a list”, [N])

    end.

 

Recur­sive Functions

A recur­sive func­tion in F# needs to be dec­o­rated with the rec key­word, a fac­to­r­ial func­tion in F# would look like this:

let rec fac n =

    match n with

    | 0 –> 1

    | _ -> n * fac(n — 1)

In Erlang, you can spec­ify mul­ti­ple over­loads (called func­tion clauses) for the same func­tion in a style sim­i­lar to facts in Pro­log, recur­sion is a sim­ple mat­ter of hav­ing one or more of these clauses call itself:

fac (N) when N =:= 0 -> 1;

fac (N) when N > 0 -> N * fac(N — 1).

You might notice that nei­ther imple­men­ta­tions above are tail recur­sive. To make tail recur­sive ver­sions of the above exam­ples, sim­ply add an accu­mu­la­tor to the func­tion, the F# ver­sion will prob­a­bly look some­thing along the lines of:

let fac n =

    let rec tail­Fac n acc =

        match n with

        | 0 –> acc

        | _ -> tail­Fac (n — 1) (n * acc)

       

    tail­Fac n 1

Notice how I imple­mented the tail recur­sive func­tion as an inner func­tion to fac so that the con­sumers of fac have a nat­ural and easy to use API and don’t have to be aware that the accu­mu­la­tor needs to be ini­tial­ized with 1 for it to func­tion cor­rectly (which is an imple­men­ta­tion detail that one should not depend upon).

This type of encap­su­la­tion is easy to achieve in Erlang and the above will trans­late nicely into:

–module(recursion).

–export([fac/1]). % only expose the fac (N) func­tion to con­sumers of this module

fac (N) -> tail_fac(N, 1).

%% these func­tions are pri­vate to the module

tail_fac (0, Acc) -> Acc;

tail_fac (N, Acc) when N > 0 -> tail_fac(N — 1, N * Acc).

 

Higher Order Functions

In F#, the List mod­ule defines a num­ber of high-order func­tions that lets you per­form map, fil­ter, zip, etc. oper­a­tions against a list, e.g. to dou­ble every ele­ment in a list you can write:

let dou­bles = List.map (fun x -> x * 2) [1..10]

// you can also write the above as the following

let doubles2 = List.map ((*) 2) [1..10]

This code will look some­thing along the line of:

Dou­bles = lists:map(fun (X) -> X * 2 end, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).

With Erlang’s anony­mous func­tions you can also spec­ify mul­ti­ple func­tion clauses like you can with a nor­mal func­tion and make use of when guards:

NewList = lists:map(fun (1) –> 10;

                                     (X) when X rem 2 =:= 0 -> X * 2;

                                     (X) -> X * 3 end,

                               [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).

Share

To install Erlang on your Mac, fol­low these sim­ple steps:

  1. down­load the lat­est source file from the offi­cial Erlang site here.
  2. open the Ter­mi­nal
  3. go to the folder where you’ve saved the .gz source file
  4. run the fol­low­ing com­mand: tar –xzf otp_src_R15B01.tar.gz (replace the file­name with the name of the file you’ve downloaded)
  5. then go into the unzipped folder in the Ter­mi­nal, e.g. cd otp_src_R15B01
  6. type in ./configure
  7. then make
  8. and finally sudo make install

voila, you’re done!

Share

Brush­ing up on Erlang again hav­ing spent so much time with F# since I last looked at Erlang, it’s star­tling how much par­al­lels I see between the two lan­guages in terms of fea­tures and syn­tax, and I’m sure it’s no coincidence Winking smile

To help myself and other F# pro­gram­mers who’re curi­ous about Erlang get started more eas­ily, I’m going to run a series of blog posts on how F# code would look in Erlang.

 

Related Posts

 

Assign­ment

Assign­ment in F# is done via the let keyword:

let x = 42

let y = 10.0

let z = x * int y

In Erlang, you just write:

1> X = 42.

42

2> Y = 10.0.

10.0

3> Z = X * Y.

420.0

It’s worth not­ing that in Erlang, vari­able names have to start with a cap­i­tal let­ter or an under­score (‘_’). Also, Erlang vari­ables can be ‘unbound’, and assigned once:

1> A. 

* 1: vari­able ‘A’ is unbound

2> A = 123.

123

3> A = 321.

** excep­tion error: no match of right hand side value 321

How­ever, you can assign the same value to a bound vari­able more than once:

1> A = 123.

123

2> A = 123.

123

This works because the equals (‘=’) oper­a­tor in Erlang is a pat­tern match oper­a­tor as opposed to assignment!

The = oper­a­tor com­pares val­ues and com­plains if they’re dif­fer­ent, if they are the same it will return the value instead. In the case of an unbound vari­able, the oper­a­tor will auto­mat­i­cally bind the right-hand side value to the vari­able on the left-hand side.

 

Wild­card

In F#, you can use the under­score ‘_’ as a wild­card to ignore the value on the right-hand side of an expression:

let _ = 42

In Erlang, it’s the same thing!

1> _ = 42.

42

 

Boolean Alge­bra

F#:

let a = true && true   // true

let b = true || false    // true

let c = not b            // false

Erlang:

1> A = true and true.

true

2> B = true or false.

true

3> C = not B.

false

In F#, the log­i­cal and (‘&&’) and log­i­cal or (‘||’) oper­a­tors will only eval­u­ate argu­ments on both sides of the oper­a­tor if nec­es­sary, so in the fol­low­ing code snip­pet only f () is evaluated:

let f () = printfn “hello”; true

let g () = printfn “world”; false

let x = f () || g ()      // prints ‘hello’

let y = g () && f ()   // prints ‘world’

In Erlang, the boolean and and or oper­a­tors will always eval­u­ate argu­ments on both sides of the oper­a­tor. If you want short-circuit behav­iour, use the andalso and orelse oper­a­tors instead.

 

Com­par­i­son

F#:

let x = 5 = 5     // true

let y = 5 <> 6   // true

let a = 5 < 6     // true

let b = 5 <= 5   // true

let c = 6 > 5     // true

let d = 5 >= 5   // true

Erlang:

1> 5 =:= 5.

true

2> 5 =/= 6.

true

3> 5 < 6.

true

4> 5 =< 5.

true

5> 6 > 5.

true

6> 5 >= 5.

true

 

Tuples

In F#, a tuple is writ­ten in the form ( Element1, Element2, … Ele­mentN ):

let point = (4, 5)

let x, y = point

In Erlang, a tuple is writ­ten in the form { Element1, Element2, …, Ele­mentN }, such as:

1> Point = { 4, 5 }.

{ 4, 5 }

2> { X, Y } = Point.

{ 4, 5 }

 

Lists

Lists in F# and Erlang are both imple­mented as linked-lists, whilst F#’s lists can hold ele­ments of the same type, Erlang’s lists can hold a mix­ture of anything.

F#:

let lst = [ 1; 2; 3; 4 ]      // [ 1; 2; 3; 4 ]

let hd = lst.Head          // hd = 1

let _::tl = lst                 // tl = [ 2; 3; 4 ]

let lst2 = 1::2::3::4::[ ]    // [ 1; 2; 3; 4 ]

Erlang:

1> Lst = [ 1, “one”, { 2, 3 } ].

[1,“one”,{2,3}]

2> hd(Lst).

1

3> [ _ | Tl ] = Lst.

[“one”,{2,3}]

4> Tl.

[“one”,{2, 3}]

6> [ 1 | [ 2 | [ 3 | [ 4 | [ ] ] ] ] ].

[1,2,3,4]

 

List Com­pre­hen­sions

You can write a sim­ple list com­pre­hen­sion in F# like this:

let lst = [ for x in [ 1..4 ] -> x * 2 ]

This code will look like this in Erlang:

1> Lst = [ X * 2 || X <- [ 1, 2, 3, 4 ] ].

[ 2, 4, 6, 8 ]

Erlang’s list com­pre­hen­sions also lets you spec­ify con­di­tions on the input for instance:

1> Lst = [ X * 2 || X <- [ 1, 2, 3, 4, 5, 6, 7, 8 ], X =< 4 ].

[ 2, 4, 6, 8 ]

Sup­port for when guards in F#’s list com­pre­hen­sion was removed quite a while back, but you can still achieve the same effect eas­ily enough with a sim­ple if conditions:

let lst = [ for x in [ 1..8 ] do if x <= 4 then yield x * 2 ]

In F#, you can also nest mul­ti­ple list comprehensions:

let lst = [ for x in [1..8] do

                  for y in [1..4] do

                      if x <= 4 then yield x, y]

To do the same in Erlang, you can spec­ify a sec­ond ‘gen­er­a­tor expression’:

Lst = [ { X, Y } || X <- [ 1, 2, 3, 4, 5, 6, 7, 8 ], Y <- [ 1, 2, 3, 4 ], X =< 4].

In gen­eral, Erlang’s list com­pre­hen­sion is of the form: [ Expres­sion || GeneratorExp1, GeneratorExp2, …, Gen­er­a­tor­ExpN, Condition1, Condition2, …, Con­di­tionM ].

 

Func­tions

In F#, you can define a func­tion using the let key­word fol­lowed by the name of the func­tion and its parameters:

let ident x = x

In Erlang, func­tions can be defined only in mod­ules, and is defined like the following:

–module(my_module).

–export([ident/1]).

ident ( X ) –> X

 

Lambda (anony­mous function)

In F#, you can declare a lambda using the fun keyword:

let add = (fun (x, y) –> x + y);

let ans = add(3, 2);     // ans = 5

Guess what, it’s fun to declare lamb­das in Erlang too Winking smile

1> Add = fun (X, Y) –> X + Y end.

#Fun<erl_eval.12.82930912>

2> Add(3, 2).

5

Share

Just fin­ished watch­ing a good video by Bryan Hunter titled Erlang for C# Devel­op­ers where he told a great story about the first project Erlang was used in inside Eric­son and how they man­aged a Nine Nines uptime with that project.

For any­one who’s won­der­ing what ‘Nine Nines’ means, it means the ser­vice is avail­able 99.9999999% of the time or, a total of 32 mil­lisec­onds of down­time a year! Unbelievable!

image

Share