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

Related Posts

 

Here I will look at how some commonly used functions in F#’s List module might be translated to Erlang using Erlang’s equivalent – the lists module.

 

List.append

F#:         let newList = List.append [ 1..5 ] [ 6..10 ]

Erlang:   NewList = lists:append([ 1, 2, 3, 4, 5 ], [ 6, 7, 8, 9, 10 ]).

List.average

F#:         let avg = List.average [ 1.0..10.0 ]

Erlang:   List = lists: seq(1, 10).

             Avg = lists: sum(List) / length(List).

List.collect

F#:         let duped = [ ‘a’; ‘b’; ‘c’ ] |> List.collect (fun x -> [ x; x ])

Erlang:   Duped = lists:flatmap(fun(X) –> [ X, X ] end, [ a, b, c ]).

List.concat

F#:         let newList = List.concat [ [ 1; 2 ]; [ 3; 4; 5 ]; [ 6; 7; 8; 9 ] ]

Erlang:   NewList = lists:append([ [ 1, 2 ], [ 3, 4, 5 ], [ 6, 7, 8, 9 ] ]).

 

List.exists

F#:         let hasEven = [ 1..2..9 ] |> List.exists (fun x -> x % 2 = 0)

Erlang:   HasEven = lists:any(fun(X) -> X rem 2 =:= 0 end, lists: seq(1, 9, 2)).

 

List.filter

F#:         let evens = [ 1.. 6 ] |> List.filter (fun x -> x % 2 = 0)

Erlang:   Evens = lists:filter(fun(X) -> X rem 2 =:= 0 end, lists:seq(1, 6)).

 

List.find

F#:         let fstMatch = [ "cui"; "xue"; "yan" ] |> List.find ((=) "yan")

Erlang:   FstMatch = lists:keyfind(yan, 1, [ { cui }, { xue }, { yan } ]).

 

List.fold

F#:         let data = [ ("Cats", 4); ("Dogs", 5); ("Mice", 3); ("Elephants", 2) ]

              let count = data |> List.fold (fun acc (_, x) -> acc + x) 0

Erlang:   Data = [ { cats, 4 }, { dogs, 5 }, { mice, 3 }, { elephants, 2 } ].

             Count = lists:foldl(fun({ _, N }, Acc) -> Acc + N end, 0, Data).

 

List.foldBack

F#:         let copy = List.foldBack (fun elem acc -> elem::acc) [ 1..10 ] []

Erlang:   Copy = lists:foldr(fun(X, Acc) -> [X|Acc] end, [], lists:seq(1, 10)).

 

List.forall

F#:         let allEven = [2; 4; 6; 8] |> List.forall (fun n -> n % 2 = 0)

Erlang:   AllEven = lists:all(fun(X) -> X rem 2 =:= 0 end, [ 2, 4, 6, 8 ]).

 

List.iter

F#:         [1..10] |> List.iter (printfn "%d")

Erlang:   lists:foreach(fun(X) -> io:format("~p~n", [ X ]) end, lists:seq(1, 10)).

 

List.length

F#:         let lst = [ 1..10 ]

              // you can call the Length property on a list

              let len1 = lst.Length

              // or use List.length

              let len2 = List.length lst

Erlang:   Lst = lists: seq(1, 10).

             % you can use the length built-in function

             Len1 = length(Lst).

             % or you can use lists:flatlength

             Len2 = lists:flatlength(Lst).

 

List.map

F#:         let doubles = [ 1..10 ] |> List.map (fun x -> x * 2)

Erlang:   Doubles = lists:map(fun(X) -> X * 2 end, lists:seq(1, 10)).

 

List.max

F#:         let max = [ 1..10 ] |> List.max

Erlang:   Max = lists:max(lists: seq(1, 10)).

 

List.min

F#:         let min = [ 1..10 ] |> List.min

Erlang:   Min = lists:min(lists: seq(1, 10)).

 

List.nth

F#:         let fourth = List.nth [ 1..10 ] 3

Erlang:   Fourth = lists:nth(4, lists: seq(1, 10)). % node that n is not zero-indexed here!

 

List.partition

F#:         let evens, odds = [ 1..10 ] |> List.partition (fun n -> n % 2 = 0)

Erlang:   { Evens, Odds } = lists:partition(fun(X) -> X rem 2 =:= 0 end, lists:seq(1, 10)).

 

List.rev

F#:         let rev = [ 1..10 ] |> List.rev

Erlang:   Rev = lists:reverse(lists: seq(1, 10)).

 

List.sort

F#:         let sorted = List.sort [ 1; 4; 7; -1; 5 ]

Erlang:   Sorted = lists:sort([ 1, 4, 7, -1, 5 ]).

 

List.sum

F#:         let sum = List.sum [ 1..10 ]

Erlang:   Sum = lists:sum(lists:seq(1, 10)).

 

List.unzip

F#:         let lstA, lstB = List.unzip [ (1, 2); (3, 4) ]

Erlang:   { LstA, LstB } = lists:unzip([ {1, 2}, {3, 4} ]).

 

List.zip

F#:         let lst = List.zip [ 1; 2 ] [ 3; 4 ]

Erlang:   Lst = lists:zip([ 1, 2 ], [ 3, 4 ]).

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

Related Posts

 

Throwing Exceptions

In F#, you can define a custom exception type by creating a type that inherit from System.Exception or using the lightweight exception syntax to define them with the same syntax as discriminated unions.

You can throw exceptions in F# using the raise keyword or using failwith or failwithf:

exception MyExceptionA

exception MyExceptionB of string

let exThrower (isA : bool option) =

    match isA with

    | Some(true) -> raise MyExceptionA

    | Some(false) -> raise <| MyExceptionB("Blah Blah")

    | _ -> raise <| new System.Exception()

    | _ -> failwith "Not a valid input"

Erlang also has a number of different exception types, the most common ways to raise an exception in Erlang is via:

  • error(Reason) – terminates the current process and includes a stack trace.
  • exit(Reason) – similar to errors, but does not return the stack trace.
  • throw(Reason) – throws exceptions that the caller can be expected to handle, also used as a way to return from deep recursion.

1> throw("Blah Blah").

** exception throw: "Blah Blah"

2> error(boo).

** exception error: boo

3> exit(foo).

** exception exit: foo

 

Catching Exceptions

In F#, you can implement a try-catch block using the try-with keywords, and it’s really easy to use pattern matching to make handling multiple types of exceptions really easy.

Borrowing from the wonderfully humorous example from Learn you some Erlang for great good! here’s how it’ll look in F#:

 

In Erlang, the syntax is surprisingly similar:

 

Another thing to keep in mind is that whilst F# has try-with and try-finally blocks there is no equivalent of C#’s try-catch-finally block. In Erlang the try-catch-finally block looks like this:

black_knight(Attack) when is_function(Attack, 0) –>

    try Attack() of

        _ -> "None shall pass."

    catch

        throw:slice   -> "It is but a scratch.";

        error:cut_arm -> "I’ve had worse.";

        exit: cut_leg -> "Come on you pansy!";

        _:_             -> "Just a flesh wound."

    after

        io:format("Attack finished…~n", [])

    end.

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

Related Posts

 

if-else

In F#, if-else if-else control 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 ultimate question of life, the universe and everything" 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 specify multiple clauses and the last catch-all (true –> …) is Erlang’s equivalent of the ‘else’ clause.

f (N) –>

    if N =:= 42 -> io:format("~p is the answer to the ultimate question of life, the universe and everything", [N]);

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

       true -> io:format("~p is odd", [N])  % this is Erlang’s equivalent to an ‘else’

    end.

When you’re writing Erlang you’re usually discouraged from using ‘else’ or ‘true’ branches altogether and should instead replace them with if clauses that cover all logical branches to help avoid masking otherwise hard-to-detect bugs.

 

match-with

The preferred way (for me at least) to do conditional branching in F# is to use the match-with expression rather than using ifs. The logic expressed in the function f from the above example can easily be expressed in a match-with instead:

let g n =

    match n with

    | 42 -> printfn "%d is the answer to the ultimate question of life, the universe and everything" n

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

    | _ -> printfn "%d is odd" n

Erlang’s counterpart to match-with is the case-of expression, which looks a lot like match-with:

g (N) –>

    case N of

        42 -> io:format("~p is the answer to the ultimate question of life, the universe and everything", [N]);

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

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

    end.

 

Type Conversions

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

let n = int “42”

provided that there exists an explicit cast operator that lets you convert a value of type T to type V.

In Erlang, type conversion is achieved with the help of built-in functions that are generally named T_to_V where T and V are the names of the source and destination types:

N = list_to_integer(“42”).

There are many other such built-in functions, including: atom_to_binary, atom_to_list, binary_to_atom, list_to_atom, integer_to_list, …

From the above example, you might be wondering why the built-in function that converts a string to an integer 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 integers whose elements are all integers that represent printable characters:

1> [52, 50].

“42”

2> % 2 is not a printable character, so this is treated as an integer list

2> [52, 50, 2].

[52, 50, 2]

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

"hello"

4> % you can use the $ operator to find out the integer value of a character

4> $/.

47

5> $n.

110

I’m sure many a developer has enjoyed a wonderful WTF moment when they realised the lack of a native string type in Erlang, but given its origin in the telecom world where string manipulation is seldom required it’s perhaps not surprising that the language designers never saw fit to make string manipulation more natural.

But seriously, WTF!

 

Type Tests

Type testing is performed with the : ? operator in F#:

let f (n : obj) =

    match n with

    | : ? int as nInt -> printfn "%d is an integer" 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 number of built-in functions 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 integer", [N]);

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

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

    end.

 

Recursive Functions

A recursive function in F# needs to be decorated with the rec keyword, a factorial function in F# would look like this:

let rec fac n =

    match n with

    | 0 –> 1

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

In Erlang, you can specify multiple overloads (called function clauses) for the same function in a style similar to facts in Prolog, recursion is a simple matter of having 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 neither implementations above are tail recursive. To make tail recursive versions of the above examples, simply add an accumulator to the function, the F# version will probably look something along the lines of:

let fac n =

    let rec tailFac n acc =

        match n with

        | 0 –> acc

        | _ -> tailFac (n – 1) (n * acc)

       

    tailFac n 1

Notice how I implemented the tail recursive function as an inner function to fac so that the consumers of fac have a natural and easy to use API and don’t have to be aware that the accumulator needs to be initialized with 1 for it to function correctly (which is an implementation detail that one should not depend upon).

This type of encapsulation is easy to achieve in Erlang and the above will translate nicely into:

-module(recursion).

-export([fac/1]). % only expose the fac (N) function to consumers of this module

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

%% these functions are private 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 module defines a number of high-order functions that lets you perform map, filter, zip, etc. operations against a list, e.g. to double every element in a list you can write:

let doubles = 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 something along the line of:

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

With Erlang’s anonymous functions you can also specify multiple function clauses like you can with a normal function 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]).

Install Erlang on a Mac

To install Erlang on your Mac, follow these simple steps:

  1. download the latest source file from the official Erlang site here.
  2. open the Terminal
  3. go to the folder where you’ve saved the .gz source file
  4. run the following command: tar –xzf otp_src_R15B01.tar.gz (replace the filename with the name of the file you’ve downloaded)
  5. then go into the unzipped folder in the Terminal, e.g. cd otp_src_R15B01
  6. type in ./configure
  7. then make
  8. and finally sudo make install

voila, you’re done!

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

Brushing up on Erlang again having spent so much time with F# since I last looked at Erlang, it’s startling how much parallels I see between the two languages in terms of features and syntax, and I’m sure it’s no coincidence Winking smile

To help myself and other F# programmers who’re curious about Erlang get started more easily, I’m going to run a series of blog posts on how F# code would look in Erlang.

 

Related Posts

 

Assignment

Assignment 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 noting that in Erlang, variable names have to start with a capital letter or an underscore (‘_’). Also, Erlang variables can be ‘unbound’, and assigned once:

1> A. 

* 1: variable ‘A’ is unbound

2> A = 123.

123

3> A = 321.

** exception error: no match of right hand side value 321

However, you can assign the same value to a bound variable more than once:

1> A = 123.

123

2> A = 123.

123

This works because the equals (‘=’) operator in Erlang is a pattern match operator as opposed to assignment!

The = operator compares values and complains if they’re different, if they are the same it will return the value instead. In the case of an unbound variable, the operator will automatically bind the right-hand side value to the variable on the left-hand side.

 

Wildcard

In F#, you can use the underscore ‘_’ as a wildcard 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 Algebra

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 logical and (‘&&’) and logical or (‘||’) operators will only evaluate arguments on both sides of the operator if necessary, so in the following code snippet 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 operators will always evaluate arguments on both sides of the operator. If you want short-circuit behaviour, use the andalso and orelse operators instead.

 

Comparison

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 written in the form ( Element1, Element2, … ElementN ):

let point = (4, 5)

let x, y = point

In Erlang, a tuple is written in the form { Element1, Element2, …, ElementN }, such as:

1> Point = { 4, 5 }.

{ 4, 5 }

2> { X, Y } = Point.

{ 4, 5 }

 

Lists

Lists in F# and Erlang are both implemented as linked-lists, whilst F#’s lists can hold elements of the same type, Erlang’s lists can hold a mixture 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 Comprehensions

You can write a simple list comprehension 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 comprehensions also lets you specify conditions on the input for instance:

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

[ 2, 4, 6, 8 ]

Support for when guards in F#’s list comprehension was removed quite a while back, but you can still achieve the same effect easily enough with a simple if conditions:

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

In F#, you can also nest multiple 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 specify a second ‘generator expression’:

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

In general, Erlang’s list comprehension is of the form: [ Expression || GeneratorExp1, GeneratorExp2, …, GeneratorExpN, Condition1, Condition2, …, ConditionM ].

 

Functions

In F#, you can define a function using the let keyword followed by the name of the function and its parameters:

let ident x = x

In Erlang, functions can be defined only in modules, and is defined like the following:

-module(my_module).

-export([ident/1]).

ident ( X ) –> X

 

Lambda (anonymous 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 lambdas in Erlang too Winking smile

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

#Fun<erl_eval.12.82930912>

2> Add(3, 2).

5