Con­sid­er­ing a very sim­ple finite state machine (FSM) such as a code lock which requires you to enter a 4-digit numeric code and upon which will open the lock for a brief few seconds.

imageSuch a FSM have two states: Locked and Open.

Every time a key is entered it checks the sequence of dig­its inputted so far and if the sequence does not match the secret code then it stays in the Locked state.

If the input sequence matches the length of the secret code then the user is judged to have entered an incor­rect sequence and the input sequence is reset.

If, on the other hand, the user has entered the cor­rect code then the FSM will change to the Open state for a num­ber of sec­onds before revert­ing back to the Locked state.

This post is intended to show you how you can imple­ment this FSM eas­ily using F#’s agent and Erlang OTP’s gen_fsm behaviour.

 

 

 

F#

First, let’s define the dif­fer­ent states that our FSM can be in:

image

and then the mes­sages that our agent can receive:

image

The actual FSM imple­men­ta­tion looks like this:

This imple­men­ta­tion is pretty straight for­ward, I’ve used a sim­i­lar tech­nique to the one Tomas Pet­ricek used in his Block­ingQueueAgent imple­men­ta­tion and rep­re­sented the dif­fer­ent states using recur­sive functions.

One caveat with this FSM is the need to revert back to the Locked state after being in the Open state for a cer­tain amount of time. For sim­plic­ity sake, I’ve sim­ply spec­i­fied a time­out (3 sec­onds) when wait­ing for mes­sages in the Open state and use the Time­ou­tEx­cep­tion as cue to go back to the Locked state. The obvi­ous down­side to my imple­men­ta­tion here is that if a Get­State mes­sage is received it will reset the timer!

You can fix this eas­ily enough in a num­ber of ways, includ­ing using a muta­ble instance vari­able to keep track of the cur­rent state and let the async lamb­das mod­ify it dur­ing state changes and tran­si­tions, then the Get­State() method would no longer need to trou­ble the agent to find out what the cur­rent state is.

 

Erlang

Erlang’s OTP frame­work pro­vide a gen_fsm behav­iour which you can use to imple­ment a FSM, which will take care of most of the plumb­ing and orches­tra­tion for you leav­ing you free to focus on the impor­tant things – han­dling the dif­fer­ent ‘events’ that can be trig­gered dur­ing dif­fer­ent states.

This Erlang imple­men­ta­tion might look much big­ger than its F# coun­ter­part but keep in mind that I’ve included plenty of com­ments here and not been as con­ser­v­a­tive with write spaces as I was with the F# code. All and all, both ver­sions require roughly the same num­ber of LOC, the main dif­fer­ence being the lack of plumb­ing in the Erlang ver­sion, which if I have to be hon­est, can be con­fus­ing if you don’t have a decent under­stand­ing of how the gen_fsm behav­iour works!

You can down­load and play around with the full source code (with cor­re­spond­ing tests for each imple­men­ta­tion) from Github here. Enjoy!

Share

Related Posts

 

Here I will look at how some com­monly used func­tions in F#’s List mod­ule might be trans­lated to Erlang using Erlang’s equiv­a­lent – 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 fst­Match = [ “cui”; “xue”; “yan” ] |> List.find ((=) “yan”)

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

 

List.fold

F#:         let data = [ (“Cats”, 4); (“Dogs”, 5); (“Mice”, 3); (“Ele­phants”, 2) ]

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

Erlang:   Data = [ { cats, 4 }, { dogs, 5 }, { mice, 3 }, { ele­phants, 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 prop­erty 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 dou­bles = [ 1..10 ] |> List.map (fun x -> x * 2)

Erlang:   Dou­bles = 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 ]).

Share

Related Posts

 

Throw­ing Exceptions

In F#, you can define a cus­tom excep­tion type by cre­at­ing a type that inherit from System.Exception or using the light­weight excep­tion syn­tax to define them with the same syn­tax as dis­crim­i­nated unions.

You can throw excep­tions in F# using the raise key­word or using fail­with or fail­withf:

excep­tion MyExceptionA

excep­tion MyEx­cep­tionB of string

let exThrower (isA : bool option) =

    match isA with

    | Some(true) -> raise MyExceptionA

    | Some(false) -> raise <| MyExceptionB(“Blah Blah”)

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

    | _ -> fail­with “Not a valid input”

Erlang also has a num­ber of dif­fer­ent excep­tion types, the most com­mon ways to raise an excep­tion in Erlang is via:

  • error(Reason) – ter­mi­nates the cur­rent process and includes a stack trace.
  • exit(Reason) – sim­i­lar to errors, but does not return the stack trace.
  • throw(Reason) – throws excep­tions that the caller can be expected to han­dle, also used as a way to return from deep recursion.

1> throw(“Blah Blah”).

** excep­tion throw: “Blah Blah”

2> error(boo).

** excep­tion error: boo

3> exit(foo).

** excep­tion exit: foo

 

Catch­ing Exceptions

In F#, you can imple­ment a try-catch block using the try-with key­words, and it’s really easy to use pat­tern match­ing to make han­dling mul­ti­ple types of excep­tions really easy.

Bor­row­ing from the won­der­fully humor­ous exam­ple from Learn you some Erlang for great good! here’s how it’ll look in F#:

 

In Erlang, the syn­tax is sur­pris­ingly similar:

 

Another thing to keep in mind is that whilst F# has try-with and try-finally blocks there is no equiv­a­lent 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.

Share

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