# Money monoid by Mark Seemann

*Kent Beck's money TDD example has some interesting properties.*

This article is part of a series about monoids. In short, a *monoid* is an associative binary operation with a neutral element (also known as *identity*).

In the first half of Test-Driven Development By Example Kent Beck explores how to develop a simple and flexible Money API using test-driven development. Towards the end, he arrives at a design that warrants further investigation.

**Kent Beck's API**

The following treatment of Kent Beck's code is based on Yawar Amin's C# reproduction of Kent Beck's original Java code, further forked and manipulated by me.

The goal of Kent Beck's exercise is to develop an object-oriented API able to handle money of multiple currencies, and for example be able to express operations such as *5 USD + 10 CHF*. Towards the end of the example, he arrives at an interface that, translated to C#, looks like this:

public interface IExpression { Money Reduce(Bank bank, string to); IExpression Plus(IExpression addend); IExpression Times(int multiplier); }

The `Reduce`

method reduces an `IExpression`

object to a single currency (`to`

), represented as a `Money`

object. This is useful if you have an `IExpression`

object that contains several currencies.

The `Plus`

method adds another `IExpression`

object to the current object, and returns a new `IExpression`

. This could be money in a single currency, but could also represent money held in more than one currency.

The `Times`

method multiplies an `IExpression`

with a multiplier. You'll notice that, throughout this example code base, both multiplier and amounts are modelled as integers. I think that Kent Beck did this as a simplification, but a more realistic example should use `decimal`

values.

The metaphor is that you can model money as one or more *expressions*. A simple expression would be *5 USD*, but you could also have *5 USD + 10 CHF* or *5 USD + 10 CHF + 10 USD*. While you can reduce some expressions, such as *5 CHF + 7 CHF*, you can't reduce an expression like *5 USD + 10 CHF* unless you have an exchange rate. Instead of attempting to reduce monetary values, this particular design builds an expression tree until you decide to evaluate it. (Sounds familiar?)

Kent Beck implements `IExpression`

twice:

`Money`

models an amount in a single currency. It contains an`Amount`

and a`Currency`

read-only property. It's the quintessential Value Object.`Sum`

models the sum of two other`IExpression`

objects. It contains two other`IExpression`

objects, called`Augend`

and`Addend`

.

*5 USD + 10 CHF*, you can write:

IExpression sum = new Sum(Money.Dollar(5), Money.Franc(10));

where `Money.Dollar`

and `Money.Franc`

are two static factory methods that return `Money`

values.

**Associativity**

Did you notice that `Plus`

is a binary operation? Could it be a monoid as well?

In order to be a monoid, it must obey the *monoid laws*, the first of which is that the operation must be associative. This means that for three `IExpression`

objects, `x`

, `y`

, and `z`

, `x.Plus(y).Plus(z)`

must be equal to `x.Plus(y.Plus(z))`

. How should you interpret equality here? The return value from `Plus`

is another `IExpression`

value, and interfaces don't have custom equality behaviour. Either, it's up to the individual implementations (`Money`

and `Sum`

) to override and implement equality, or you can use test-specific equality.

The xUnit.net assertion library supports test-specific equality via custom comparers (for more details, see my Advanced Unit Testing Pluralsight course). The original Money API does, however, already include a way to compare expressions!

The `Reduce`

method can reduce any `IExpression`

to a single `Money`

object (that is, to a single currency), and since `Money`

is a Value Object, it has structural equality. You can use this to compare the values of `IExpression`

objects. All you need is an exchange rate.

In the book, Kent Beck uses a 2:1 exchange rate between CHF and USD. As I'm writing this, the exchange rate is 0.96 Swiss Franc to a Dollar, but since the example code consistently models money as integers, that rounds to a 1:1 exchange rate. This is, however, a degenerate case, so instead, I'm going to stick to the book's original 2:1 exchange rate.

You can now add an Adapter between `Reduce`

and xUnit.net in the form of an `IEqualityComparer<IExpression>`

:

public class ExpressionEqualityComparer : IEqualityComparer<IExpression> { private readonly Bank bank; public ExpressionEqualityComparer() { bank = new Bank(); bank.AddRate("CHF", "USD", 2); } public bool Equals(IExpression x, IExpression y) { var xm = bank.Reduce(x, "USD"); var ym = bank.Reduce(y, "USD"); return object.Equals(xm, ym); } public int GetHashCode(IExpression obj) { return bank.Reduce(obj, "USD").GetHashCode(); } }

You'll notice that this custom equality comparer uses a `Bank`

object with a 2:1 exchange rate. `Bank`

is another object from the *Test-Driven Development* example. It doesn't implement any interface itself, but it does appear as an argument in the `Reduce`

method.

In order to make your test code more readable, you can add a static helper class:

public static class Compare { public static ExpressionEqualityComparer UsingBank = new ExpressionEqualityComparer(); }

This enables you to write an assertion for associativity like this:

Assert.Equal( x.Plus(y).Plus(z), x.Plus(y.Plus(z)), Compare.UsingBank);

In my fork of Yawar Amin's code base, I added this assertion to an FsCheck-based automated test, and it holds for all the `Sum`

and `Money`

objects that FsCheck generates.

In its present incarnation, `IExpression.Plus`

is associative, but it's worth noting that this isn't guaranteed to last. An interface like `IExpression`

is an extensibility point, so someone could easily add a third implementation that would violate associativity. We can tentatively conclude that `Plus`

is currently associative, but that the situation is delicate.

**Identity**

If you accept that `IExpression.Plus`

is associative, it's a monoid candidate. If an identity element exists, then it's a monoid.

Kent Beck never adds an identity element in his book, but you can add one yourself:

public static class Plus { public readonly static IExpression Identity = new PlusIdentity(); private class PlusIdentity : IExpression { public IExpression Plus(IExpression addend) { return addend; } public Money Reduce(Bank bank, string to) { return new Money(0, to); } public IExpression Times(int multiplier) { return this; } } }

There's only a single identity element, so it makes sense to make it a Singleton. The private `PlusIdentity`

class is a new `IExpression`

implementation that deliberately doesn't do anything.

In `Plus`

, it simply returns the input expression. This is the same behaviour as zero has for integer addition. When adding numbers together, zero is the identity element, and the same is the case here. This is more explicitly visible in the `Reduce`

method, where the identity expression simply reduces to zero in the requested currency. Finally, if you multiply the identity element, you still get the identity element. Here, interestingly, `PlusIdentity`

behaves similar to the identity element for multiplication (*1*).

You can now write the following assertions for any `IExpression x`

:

Assert.Equal(x, x.Plus(Plus.Identity), Compare.UsingBank); Assert.Equal(x, Plus.Identity.Plus(x), Compare.UsingBank);

Running this as a property-based test, it holds for all `x`

generated by FsCheck. The same caution that applies to associativity also applies here: `IExpression`

is an extensibility point, so you can't be sure that `Plus.Identity`

will be the identity element for all `IExpression`

implementations someone could create, but for the three implementations that now exist, the monoid laws hold.

`IExpression.Plus`

is a monoid.

**Multiplication**

In basic arithmetic, the multiplication operator is called *times*. When you write *3 * 5*, it literally means that you have 3 five times (or do you you have 5 three times?). In other words:

3 * 5 = 3 + 3 + 3 + 3 + 3

Does a similar relationship exist for `IExpression`

?

Perhaps, we can take a hint from Haskell, where monoids and semigroups are explicit parts of the core library. You're going to learn about semigroups later, but for now, it's interesting to observe that the `Semigroup`

typeclass defines a function called `stimes`

, which has the type `Integral b => b -> a -> a`

. Basically, what this means that for any integer type (16-bit integer, 32-bit integer, etc.) `stimes`

takes an integer and a value `a`

and 'multiplies' the value. Here, `a`

is a type for which a binary operation exists.

In C# syntax, `stimes`

would look like this as an instance method on a `Foo`

class:

public Foo Times(int multiplier)

I named the method `Times`

instead of `STimes`

, since I strongly suspect that the *s* in Haskell's `stimes`

stands for `Semigroup`

.

Notice how this is the same type of signature as `IExpression.Times`

.

If it's possible to define a universal implementation of such a function in Haskell, could you do the same in C#? In `Money`

, you can implement `Times`

based on `Plus`

:

public IExpression Times(int multiplier) { return Enumerable .Repeat((IExpression)this, multiplier) .Aggregate((x, y) => x.Plus(y)); }

The static `Repeat`

LINQ method returns `this`

as many times as requested by `multiplier`

. The return value is an `IEnumerable<IExpression>`

, but according to the `IExpression`

interface, `Times`

must return a single `IExpression`

value. You can use the `Aggregate`

LINQ method to repeatedly combine two `IExpression`

values (`x`

and `y`

) to one, using the `Plus`

method.

This implementation is hardly as efficient as the previous, individual implementation, but the point here isn't about efficiency, but about a common, reusable abstraction. The exact same implementation can be used to implement `Sum.Times`

:

public IExpression Times(int multiplier) { return Enumerable .Repeat((IExpression)this, multiplier) .Aggregate((x, y) => x.Plus(y)); }

This is literally the same code as for `Money.Times`

. You can also copy and paste this code to `PlusIdentity.Times`

, but I'm not going to repeat it here, because it's the same code as above.

This means that you can remove the `Times`

method from `IExpression`

:

public interface IExpression { Money Reduce(Bank bank, string to); IExpression Plus(IExpression addend); }

Instead, you can implement it as an extension method:

public static class Expression { public static IExpression Times(this IExpression exp, int multiplier) { return Enumerable .Repeat(exp, multiplier) .Aggregate((x, y) => x.Plus(y)); } }

This works because any `IExpression`

object has a `Plus`

method.

As I've already admitted, this is likely to be less efficient than specialised implementations of `Times`

. In Haskell, this is addressed by making `stimes`

part of the typeclass, so that implementers can implement a more efficient algorithm than the default implementation. In C#, the same effect could be achieved by refactoring `IExpression`

to an abstract base class, with `Times`

as a public virtual (overridable) method.

**Haskell sanity check**

Since Haskell has a more formal definition of a monoid, you may want to try to port Kent Beck's API to Haskell, as a proof of concept. In its final modification, my C# fork has three implementations of `IExpression`

:

`Money`

`Sum`

`PlusIdentity`

data Expression = Money { amount :: Int, currency :: String } | Sum { augend :: Expression, addend :: Expression } | MoneyIdentity deriving (Show)

You can formally make this a `Monoid`

:

instance Monoid Expression where mempty = MoneyIdentity mappend MoneyIdentity y = y mappend x MoneyIdentity = x mappend x y = Sum x y

The C# `Plus`

method is here implemented by the `mappend`

function. The only remaining member of `IExpression`

is `Reduce`

, which you can implement like this:

import Data.Map.Strict (Map, (!)) reduce :: Ord a => Map (String, a) Int -> a -> Expression -> Int reduce bank to (Money amt cur) = amt `div` rate where rate = bank ! (cur, to) reduce bank to (Sum x y) = reduce bank to x + reduce bank to y reduce _ _ MoneyIdentity = 0

Haskell's typeclass mechanism takes care of the rest, so that, for example, you can reproduce one of Kent Beck's original tests like this:

λ> let bank = fromList [(("CHF","USD"),2), (("USD", "USD"),1)] λ> let sum = stimesMonoid 2 $ MoneyPort.Sum (Money 5 "USD") (Money 10 "CHF") λ> reduce bank "USD" sum 20

Just like `stimes`

works for any `Semigroup`

, `stimesMonoid`

is defined for any `Monoid`

, and therefore you can also use it with `Expression`

.

With the historical 2:1 exchange rate, 5 Dollars + 10 Swiss Franc, times 2, is equivalent to 20 Dollars.

**Summary**

In chapter 17 of his book, Kent Beck describes that he'd been TDD'ing a Money API many times before trying out the expression-based API he ultimately used in the book. In other words, he had much experience, both with this particular problem, and with programming in general. Clearly this is a highly skilled programmer at work.

I find it interesting that he seems to intuitively arrive at a design involving a monoid and an interpreter. If he did this on purpose, he doesn't say so in the book, so I rather speculate that he arrived at the design simply because he recognised its superiority. This is the reason that I find it interesting to identify this, *an existing example*, as a monoid, because it indicates that there's something supremely comprehensible about monoid-based APIs. It's conceptually 'just like addition'.

In this article, we returned to a decade-old code example in order to identify it as a monoid. In the next article, I'm going to revisit an example code base of mine from 2015.

**Next: ** Convex hull monoid.

## Comments

Actually, in a lot of financial systems money is stored in cents, and therefore as integers, because it avoids rounding errors.

Great articles btw! :)

Hrvoje, thank you for writing. Yes, it's a good point that you could model the values as cents and rappen, but I think I recall that Kent Beck's text distinctly discusses

dollarsandfrancs. I am, however, currently travelling, without access to the book, so I can't check.The scenario, as simplistic as it may be, involves currency exchange, and exchange rates tend to involve much smaller fractions. As an example, right now, one currency exchange web site reports that 1 CHF is 1.01950 USD. Clearly, representing the U.S. currency with cents would incur a loss of precision, because that would imply an exchange rate of 102 cents to 100 rappen. I'm sure arbitrage opportunities would be legion if you ever wrote code like that.

If I remember number theory correctly, you can always scale any rational number to an integer. I.e. in this case, you could scale 1.01950 to 101,950. There's little reason to do that, because you have the

All of this, however, is just idle speculation on my point. I admit that I've never had to implement complex financial calculations, so there may be some edge cases of which I'm not aware. For all the run-of-the-mill eCommerce and payment solutions I've implemented over the years,`decimal`

struct for that purpose:`decimal`

has always been more than adequate.