Part of the "Annotated walkthroughs" series (link)

# Calculator Walkthrough: Part 2

Testing the design with a trial implementation

In this post, I’ll continue developing a simple pocket calculator app, like this: In the previous post, we completed a first draft of the design, using only types (no UML diagrams!).

Now it’s time to create a trial implementation that uses the design.

Doing some real coding at this point acts as a reality check. It ensures that the domain model actually makes sense and is not too abstract. And of course, it often drives more questions about the requirements and domain model.

## First implementation

So let’s try implementing the main calculator function, and see how we do.

First, we can immediately create a skeleton that matches each kind of input and processes it accordingly.

``````let createCalculate (services:CalculatorServices) :Calculate =
fun (input,state) ->
match input with
| Digit d ->
let newState = // do something
newState //return
| Op op ->
let newState = // do something
newState //return
| Action Clear ->
let newState = // do something
newState //return
| Action Equals ->
let newState = // do something
newState //return
``````

You can see that this skeleton has a case for each type of input to handle it appropriately. Note that in all cases, a new state is returned.

This style of writing a function might look strange though. Let’s look at it a bit more closely.

First, we can see that `createCalculate` is the not the calculator function itself, but a function that returns another function. The returned function is a value of type `Calculate` – that’s what the `:Calculate` at the end means.

Here’s just the top part:

``````let createCalculate (services:CalculatorServices) :Calculate =
fun (input,state) ->
match input with
// code
``````

Since it is returning a function, I chose to write it using a lambda. That’s what the `fun (input,state) -> ` is for.

But I could have also written it using an inner function, like this

``````let createCalculate (services:CalculatorServices) :Calculate =
let innerCalculate (input,state) =
match input with
// code
innerCalculate // return the inner function
``````

Both approaches are basically the same* – take your pick!

* Although there might be some performance differences.

## Dependency injection of services

But `createCalculate` doesn’t just return a function, it also has a `services` parameter. This parameter is used for doing the “dependency injection” of the services.

That is, the services are only used in `createCalculate` itself, and are not visible in the function of type `Calculate` that is returned.

The “main” or “bootstrapper” code that assembles all the components for the application would look something like this:

``````// create the services
let services = CalculatorServices.createServices()

// inject the services into the "factory" method
let calculate = CalculatorImplementation.createCalculate services

// the returned "calculate" function is of type Calculate
// and can be passed into the UI, for example

// create the UI and run it
let form = new CalculatorUI.CalculatorForm(calculate)
form.Show()
``````

## Implementation: handling digits

Now let’s start implementing the various parts of the calculation function. We’ll start with the digits handling logic.

To keep the main function clean, let’s pass the responsibility for all the work to a helper function `updateDisplayFromDigit`, like this:

``````let createCalculate (services:CalculatorServices) :Calculate =
fun (input,state) ->
match input with
| Digit d ->
let newState = updateDisplayFromDigit services d state
newState //return
``````

Note that I’m creating a `newState` value from the result of `updateDisplayFromDigit` and then returning it as a separate step.

I could have done the same thing in one step, without an explicit `newState` value, as shown below:

``````let createCalculate (services:CalculatorServices) :Calculate =
fun (input,state) ->
match input with
| Digit d ->
updateDisplayFromDigit services d state
``````

Neither approach is automatically best. I would pick one or the other depending on the context.

For simple cases, I would avoid the extra line as being unnecessary, but sometimes having an explicit return value is more readable. The name of the value tells you an indication of the return type, and it gives you something to watch in the debugger, if you need to.

Alright, let’s implement `updateDisplayFromDigit` now. It’s pretty straightforward.

• first use the `updateDisplayFromDigit` in the services to actually update the display
• then create a new state from the new display and return it.
``````let updateDisplayFromDigit services digit state =
let newDisplay = services.updateDisplayFromDigit (digit,state.display)
let newState = {state with display=newDisplay}
newState //return
``````

## Implementation: handling Clear and Equals

Before we move onto the implementation of the math operations, lets look at handling `Clear` and `Equals`, as they are simpler.

For `Clear`, just init the state, using the provided `initState` service.

For `Equals`, we check if there is a pending math op. If there is, run it and update the display, otherwise do nothing. We’ll put that logic in a helper function called `updateDisplayFromPendingOp`.

So here’s what `createCalculate` looks like now:

``````let createCalculate (services:CalculatorServices) :Calculate =
fun (input,state) ->
match input with
| Digit d -> // as above
| Op op -> // to do
| Action Clear ->
let newState = services.initState()
newState //return
| Action Equals ->
let newState = updateDisplayFromPendingOp services state
newState //return
``````

Now to `updateDisplayFromPendingOp`. I spent a few minutes thinking about, and I’ve come up with the following algorithm for updating the display:

• First, check if there is any pending op. If not, then do nothing.
• Next, try to get the current number from the display. If you can’t, then do nothing.
• Next, run the op with the pending number and the current number from the display. If you get an error, then do nothing.
• Finally, update the display with the result and return a new state.
• The new state also has the pending op set to `None`, as it has been processed.

And here’s what that logic looks like in imperative style code:

``````// First version of updateDisplayFromPendingOp
// * very imperative and ugly
let updateDisplayFromPendingOp services state =
if state.pendingOp.IsSome then
let op,pendingNumber = state.pendingOp.Value
let currentNumberOpt = services.getDisplayNumber state.display
if currentNumberOpt.IsSome then
let currentNumber = currentNumberOpt.Value
let result = services.doMathOperation (op,pendingNumber,currentNumber)
match result with
| Success resultNumber ->
let newDisplay = services.setDisplayNumber resultNumber
let newState = {display=newDisplay; pendingOp=None}
newState //return
| Failure error ->
state // original state is untouched
else
state // original state is untouched
else
state // original state is untouched
``````

Ewww! Don’t try that at home!

That code does follow the algorithm exactly, but is really ugly and also error prone (using `.Value` on an option is a code smell).

On the plus side, we did make extensive use of our “services”, which has isolated us from the actual implementation details.

So, how can we rewrite it to be more functional?

## Bumping into bind

The trick is to recognize that the pattern “if something exists, then act on that value” is exactly the `bind` pattern discussed here and here.

In order to use the bind pattern effectively, it’s a good idea to break the code into many small chunks.

First, the code `if state.pendingOp.IsSome then do something` can be replaced by `Option.bind`.

``````let updateDisplayFromPendingOp services state =
let result =
state.pendingOp
|> Option.bind ???
``````

But remember that the function has to return a state. If the overall result of the bind is `None`, then we have not created a new state, and we must return the original state that was passed in.

This can be done with the built-in `defaultArg` function which, when applied to an option, returns the option’s value if present, or the second parameter if `None`.

``````let updateDisplayFromPendingOp services state =
let result =
state.pendingOp
|> Option.bind ???
defaultArg result state
``````

You can also tidy this up a bit as well by piping the result directly into `defaultArg`, like this:

``````let updateDisplayFromPendingOp services state =
state.pendingOp
|> Option.bind ???
|> defaultArg <| state
``````

I admit that the reverse pipe for `state` looks strange – it’s definitely an acquired taste!

Onwards! Now what about the parameter to `bind`? When this is called, we know that pendingOp is present, so we can write a lambda with those parameters, like this:

``````let result =
state.pendingOp
|> Option.bind (fun (op,pendingNumber) ->
let currentNumberOpt = services.getDisplayNumber state.display
// code
)
``````

Alternatively, we could create a local helper function instead, and connect it to the bind, like this:

``````let executeOp (op,pendingNumber) =
let currentNumberOpt = services.getDisplayNumber state.display
/// etc

let result =
state.pendingOp
|> Option.bind executeOp
``````

I myself generally prefer the second approach when the logic is complicated, as it allows a chain of binds to be simple. That is, I try to make my code look like:

``````let doSomething input = return an output option
let doSomethingElse input = return an output option
let doAThirdThing input = return an output option

state.pendingOp
|> Option.bind doSomething
|> Option.bind doSomethingElse
|> Option.bind doAThirdThing
``````

Note that in this approach, each helper function has a non-option for input but always must output an option.

## Using bind in practice

Once we have the pending op, the next step is to get the current number from the display so we can do the addition (or whatever).

Rather than having a lot of logic, I’m going keep the helper function (`getCurrentNumber`) simple.

• The input is the pair (op,pendingNumber)
• The output is the triple (op,pendingNumber,currentNumber) if currentNumber is `Some`, otherwise `None`.

In other words, the signature of `getCurrentNumber` will be `pair -> triple option`, so we can be sure that is usable with the `Option.bind` function.

How to convert the pair into the triple? This can be done just by using `Option.map` to convert the currentNumber option to a triple option. If the currentNumber is `Some`, then the output of the map is `Some triple`. On the other hand, if the currentNumber is `None`, then the output of the map is `None` also.

``````let getCurrentNumber (op,pendingNumber) =
let currentNumberOpt = services.getDisplayNumber state.display
currentNumberOpt
|> Option.map (fun currentNumber -> (op,pendingNumber,currentNumber))

let result =
state.pendingOp
|> Option.bind getCurrentNumber
|> Option.bind ???
``````

We can rewrite `getCurrentNumber` to be a bit more idiomatic by using pipes:

``````let getCurrentNumber (op,pendingNumber) =
state.display
|> services.getDisplayNumber
|> Option.map (fun currentNumber -> (op,pendingNumber,currentNumber))
``````

Now that we have a triple with valid values, we have everything we need to write a helper function for the math operation.

• It takes a triple as input (the output of `getCurrentNumber`)
• It does the math operation
• It then pattern matches the Success/Failure result and outputs the new state if applicable.
``````let doMathOp (op,pendingNumber,currentNumber) =
let result = services.doMathOperation (op,pendingNumber,currentNumber)
match result with
| Success resultNumber ->
let newDisplay = services.setDisplayNumber resultNumber
let newState = {display=newDisplay; pendingOp=None}
Some newState //return something
| Failure error ->
None // failed
``````

Note that, unlike the earlier version with nested ifs, this version returns `Some` on success and `None` on failure.

## Displaying errors

Writing the code for the `Failure` case made me realize something. If there is a failure, we are not displaying it at all, just leaving the display alone. Shouldn’t we show an error or something?

Hey, we just found a requirement that got overlooked! This is why I like to create an implementation of the design as soon as possible. Writing real code that deals with all the cases will invariably trigger a few “what happens in this case?” moments.

So how are we going to implement this new requirement?

In order to do this, we’ll need a new “service” that accepts a `MathOperationError` and generates a `CalculatorDisplay`.

``````type SetDisplayError = MathOperationError -> CalculatorDisplay
``````

and we’ll need to add it to the `CalculatorServices` structure too:

``````type CalculatorServices = {
// as before
setDisplayNumber: SetDisplayNumber
setDisplayError: SetDisplayError
initState: InitState
}
``````

`doMathOp` can now be altered to use the new service. Both `Success` and `Failure` cases now result in a new display, which in turn is wrapped in a new state.

``````let doMathOp (op,pendingNumber,currentNumber) =
let result = services.doMathOperation (op,pendingNumber,currentNumber)
let newDisplay =
match result with
| Success resultNumber ->
services.setDisplayNumber resultNumber
| Failure error ->
services.setDisplayError error
let newState = {display=newDisplay;pendingOp=None}
Some newState //return something
``````

I’m going to leave the `Some` in the result, so we can stay with `Option.bind` in the result pipeline*.

* An alternative would be to not return `Some`, and then use `Option.map` in the result pipeline

Putting it all together, we have the final version of `updateDisplayFromPendingOp`. Note that I’ve also added a `ifNone` helper that makes defaultArg better for piping.

``````// helper to make defaultArg better for piping
let ifNone defaultValue input =
// just reverse the parameters!
defaultArg input defaultValue

// Third version of updateDisplayFromPendingOp
// * Updated to show errors on display in Failure case
// * replaces awkward defaultArg syntax
let updateDisplayFromPendingOp services state =
// helper to extract CurrentNumber
let getCurrentNumber (op,pendingNumber) =
state.display
|> services.getDisplayNumber
|> Option.map (fun currentNumber -> (op,pendingNumber,currentNumber))

// helper to do the math op
let doMathOp (op,pendingNumber,currentNumber) =
let result = services.doMathOperation (op,pendingNumber,currentNumber)
let newDisplay =
match result with
| Success resultNumber ->
services.setDisplayNumber resultNumber
| Failure error ->
services.setDisplayError error
let newState = {display=newDisplay;pendingOp=None}
Some newState //return something

// connect all the helpers
state.pendingOp
|> Option.bind getCurrentNumber
|> Option.bind doMathOp
|> ifNone state // return original state if anything fails
``````

## Using a “maybe” computation expression instead of bind

So far, we’ve being using “bind” directly. That has helped by removing the cascading `if/else`.

But F# allows you to hide the complexity in a different way, by creating computation expressions.

Since we are dealing with Options, we can create a “maybe” computation expression that allows clean handling of options. (If we were dealing with other types, we would need to create a different computation expression for each type).

Here’s the definition – only four lines!

``````type MaybeBuilder() =
member this.Bind(x, f) = Option.bind f x
member this.Return(x) = Some x

let maybe = new MaybeBuilder()
``````

With this computation expression available, we can use `maybe` instead of bind, and our code would look something like this:

``````let doSomething input = return an output option
let doSomethingElse input = return an output option
let doAThirdThing input = return an output option

let finalResult = maybe {
let! result1 = doSomething
let! result2 = doSomethingElse result1
let! result3 = doAThirdThing result2
return result3
}
``````

In our case, then we can write yet another version of `updateDisplayFromPendingOp` – our fourth!

``````// Fourth version of updateDisplayFromPendingOp
// * Changed to use "maybe" computation expression
let updateDisplayFromPendingOp services state =

// helper to do the math op
let doMathOp (op,pendingNumber,currentNumber) =
let result = services.doMathOperation (op,pendingNumber,currentNumber)
let newDisplay =
match result with
| Success resultNumber ->
services.setDisplayNumber resultNumber
| Failure error ->
services.setDisplayError error
{display=newDisplay;pendingOp=None}

// fetch the two options and combine them
let newState = maybe {
let! (op,pendingNumber) = state.pendingOp
let! currentNumber = services.getDisplayNumber state.display
return doMathOp (op,pendingNumber,currentNumber)
}
newState |> ifNone state
``````

Note that in this implementation, I don’t need the `getCurrentNumber` helper any more, as I can just call `services.getDisplayNumber` directly.

So, which of these variants do I prefer?

It depends.

• If there is a very strong “pipeline” feel, as in the ROP approach, then I prefer using an explicit `bind`.
• On the other hand, if I am pulling options from many different places, and I want to combine them in various ways, the `maybe` computation expression makes it easier.

So, in this case, I’ll go for the last implementation, using `maybe`.

## Implementation: handling math operations

Now we are ready to do the implementation of the math operation case.

First, if there is a pending operation, the result will be shown on the display, just as for the `Equals` case. But in addition, we need to push the new pending operation onto the state as well.

For the math operation case, then, there will be two state transformations, and `createCalculate` will look like this:

``````let createCalculate (services:CalculatorServices) :Calculate =
fun (input,state) ->
match input with
| Digit d -> // as above
| Op op ->
let newState1 = updateDisplayFromPendingOp services state
let newState2 = addPendingMathOp services op newState1
newState2 //return
``````

We’ve already defined `updateDisplayFromPendingOp` above. So we just need `addPendingMathOp` as a helper function to push the operation onto the state.

The algorithm for `addPendingMathOp` is:

• Try to get the current number from the display. If you can’t, then do nothing.
• Update the state with the op and current number.

Here’s the ugly version:

``````// First version of addPendingMathOp
// * very imperative and ugly
let addPendingMathOp services op state =
let currentNumberOpt = services.getDisplayNumber state.display
if currentNumberOpt.IsSome then
let currentNumber = currentNumberOpt.Value
let pendingOp = Some (op,currentNumber)
let newState = {state with pendingOp=pendingOp}
newState //return
else
state // original state is untouched
``````

Again, we can make this more functional using exactly the same techniques we used for `updateDisplayFromPendingOp`.

So here’s the more idiomatic version using `Option.map` and a `newStateWithPending` helper function:

``````// Second version of addPendingMathOp
// * Uses "map" and helper function
let addPendingMathOp services op state =
let newStateWithPending currentNumber =
let pendingOp = Some (op,currentNumber)
{state with pendingOp=pendingOp}

state.display
|> services.getDisplayNumber
|> Option.map newStateWithPending
|> ifNone state
``````

And here’s one using `maybe`:

``````// Third version of addPendingMathOp
// * Uses "maybe"
let addPendingMathOp services op state =
maybe {
let! currentNumber =
state.display |> services.getDisplayNumber
let pendingOp = Some (op,currentNumber)
return {state with pendingOp=pendingOp}
}
|> ifNone state // return original state if anything fails
``````

As before, I’d probably go for the last implementation using `maybe`. But the `Option.map` one is fine too.

## Implementation: review

Now we’re done with the implementation part. Let’s review the code:

``````let updateDisplayFromDigit services digit state =
let newDisplay = services.updateDisplayFromDigit (digit,state.display)
let newState = {state with display=newDisplay}
newState //return

let updateDisplayFromPendingOp services state =

// helper to do the math op
let doMathOp (op,pendingNumber,currentNumber) =
let result = services.doMathOperation (op,pendingNumber,currentNumber)
let newDisplay =
match result with
| Success resultNumber ->
services.setDisplayNumber resultNumber
| Failure error ->
services.setDisplayError error
{display=newDisplay;pendingOp=None}

// fetch the two options and combine them
let newState = maybe {
let! (op,pendingNumber) = state.pendingOp
let! currentNumber = services.getDisplayNumber state.display
return doMathOp (op,pendingNumber,currentNumber)
}
newState |> ifNone state

let addPendingMathOp services op state =
maybe {
let! currentNumber =
state.display |> services.getDisplayNumber
let pendingOp = Some (op,currentNumber)
return {state with pendingOp=pendingOp}
}
|> ifNone state // return original state if anything fails

let createCalculate (services:CalculatorServices) :Calculate =
fun (input,state) ->
match input with
| Digit d ->
let newState = updateDisplayFromDigit services d state
newState //return
| Op op ->
let newState1 = updateDisplayFromPendingOp services state
let newState2 = addPendingMathOp services op newState1
newState2 //return
| Action Clear ->
let newState = services.initState()
newState //return
| Action Equals ->
let newState = updateDisplayFromPendingOp services state
newState //return
``````

Not bad – the whole implementation is less than 60 lines of code.

## Summary

We have proved that our design is reasonable by making an implementation – plus we found a missed requirement.

In the next post, we’ll implement the services and the user interface to create a complete application.

The code for this post is available in this gist on GitHub.