What does this F# code look like in Erlang – Part 1 of N

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 coin­ci­dence Winking smile

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

 

Relat­ed Posts

 

Assign­ment

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

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 val­ue 321

How­ev­er, you can assign the same val­ue 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 assign­ment!

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 val­ue instead. In the case of an unbound vari­able, the oper­a­tor will auto­mat­i­cal­ly bind the right-hand side val­ue 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 val­ue on the right-hand side of an expres­sion:

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 eval­u­at­ed:

let f () = printfn “hel­lo”; true

let g () = printfn “world”; false

let x = f () || g ()      // prints ‘hel­lo’

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-cir­cuit behav­iour, use the andal­so 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­ment­ed as linked-lists, whilst F#’s lists can hold ele­ments of the same type, Erlang’s lists can hold a mix­ture of any­thing.

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­i­fy 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­i­ly enough with a sim­ple if con­di­tions:

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 com­pre­hen­sions:

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­i­fy a sec­ond ‘gen­er­a­tor expres­sion’:

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

In gen­er­al, Erlang’s list com­pre­hen­sion is of the form: [ Expres­sion || GeneratorExp1, GeneratorExp2, …, Gen­er­a­tor­Ex­pN, 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 para­me­ters:

let ident x = x

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

-module(my_module).

-export([ident/1]).

ident ( X ) –> X

 

Lamb­da (anony­mous func­tion)

In F#, you can declare a lamb­da using the fun key­word:

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