Tutorial: Counter Application

3 Thinking About Counting

Define the Counter Process

Now that we have our communication methods in place we should set about defining the operations of counter process. This is the actual running loop that will manage the counter variable and respond to requests. Because we've already defined how we need to interact with this process, the construction is quite straight forward:

First we'll build our counter function to be our start the process from 0.

(defun counter ()
  "Runs our actual counter loop."
  (counter-loop 0))

No real surprises there, start our loop with our initial counter variable.

Now for our counter-loop function!

(defun counter-loop (count)
  (receive
    ((tuple incr)
     (counter-loop (+ count 1)))
    ((tuple 'count requestor)
     (! requestor (tuple 'count count))
     (counter-loop count))))

Pretty simple. Our initial value is passed in and the process waits to receive a message telling it to either increment the counter or return the current value.

Testing It Out

Lets take it out for a spin:

> (c '"counter.lfe")
#(module counter)
> (set foo (: counter new))
<0.35.0>
> (: counter count foo)
0
> (: counter incr foo)
#(incr)
> (: counter incr foo)
#(incr)
> (: counter count foo)
2

Success! We create a new counter process and store the pid in foo, then we ask for the current value, which is zero because we haven't incremented it yet. Increment the value a couple of times and ask for the current value which is now two! Yay.

Touch Up

Of course there are some things missing from this example, although creating a module to only hold a counter variable is slightly excessive (but not always!). Our counter process has no way to handle a malformed message, lets fix that.

(defun counter-loop (count)
  (receive
    ((tuple 'incr)
     (counter-loop (+ count 1)))
    ((tuple 'count requestor)
     (! requestor (tuple 'count count))
     (counter-loop count))
    (msg
     (: io format '"Unknown message received ~p~n", msg)
     (counter-loop count))))

We simply extend our receive patterns to include a wildcard that responds with the appropriate message, and call the counter-loop again so we can contiue waiting for other requests.. See how easy that was, now you have no excuses for not handling unknown messages! Although you will most likely want to do something more clever than simply printing a message and happily trunding along, but you get the idea.

That will probably do for now, feel free to give your counter another whirl in the shell to make sure everything still works, but the end result should look something similar to this: