Menu

Follow me

Modelling money in Elm

After reading the blog post of Mathias Verraes (@mathiasverraes) on (Type Safety and Money)[http://verraes.net/2016/02/type-safety-and-money/], and after doing a real short modelling attempt in Haskell at Socrates Belgium, I wanted to try to model Money in Elm.

I don’t want to go to deep and too far so I’ve set some basic constraints for myself:

The goal is to explore different ways of modelling the money in Elm and to explore how a type safe language can support our constraints.

Possible type declarations of Money in Elm

Money is an amount (Float) and a currency

If you are doing serious calculations with money, you might want to check if you don’t run into precision issues with Float. This is not the goal of the exercise, so we use Float.

There are some different options for modelling the money.

With a Tuple, a Currency and a Float:

typealiasMoney= (Currency, Float)
typeCurrency=Euro|Dollar

Or with union types

typeMoney=EuroFloat|DollarFloat

Both these implementations fulfill the requirement of a Money type for the Price.

These implementations cannot enforce the add constraint at compile time. Although, you can enforce that you don’t get wrong results:

add:Money->Money->MaybeMoney

or, there can be invalid money

typeMoney=EuroFloat|DollarFloat|Invalidadd:Money->Money->Money

This last one would be harder to implement with a Tuple. But in most other ways I believe the Tuple and the union types are very similar. I like the union types better, so I won’t explore the tuple any further.

When we have the choice between these 2 add type definitions, which one is best?
I prefer add : Money -> Money -> Maybe Money for 2 reasons: (1) Invalid is not an actual type of money and (2) returning Maybe makes it very explicit that this an operation that can fail.

Would it be possible to enforce the constraint of adding only the same currencies on compile time? Yes, like this:

typeEuro=EuroFloattypeDollar=DollarFloat

Now you have to implement 2 add functions for both types.

This does have some disadvantages, you have to implement add twice. If you want to have them in the same file, the names of the add methods can’t be the same, and we need some type to represent money (for our price constraint).
This also means that it’s best to implement Euro and Dollar both in their own module, so that you can create 2 add functions.

But lets see if this is doable.

First the problem of the reimplementation. This is something that is unavailable in Elm (I believe it’s possible to avoid this with type classes in Haskell), but it’s not that bad.
Suppose we needed to write many functions on money types, then we could write them like this:

Conclusion

Elm doesn’t have type classes so some things are extra work and are a bit more verbose. But it is possible to enforce a lot at compile time. Furthermore everything is very readable.

Is it worth it of doing it like this? That totally depends on your use case. A lot of times you will want to use type Money = EUR Float | USD Float and use a Maybe type to enforce your constraints, but sometimes you will do the extra work to enforce some things at compile time.

Update 2016-04-18

Zach May left a nice comment (Thanks!) on the blog about an alternative solution:

This solution also enforces strict types when adding money with the advantage that you only need one implementation for add. A possible downside could be if you want your money types to have different number types (for example if you want to model bitcoins not with Ints but with SomeBitcoinNumberType). But like I said in my conclusion, you have to look at your constraints and chose a solution yourself.