# Adding Meaning to Primitive Types in fsharp

One of the recommended guidelines in Domain Driven Design is modelling the domain ideas using the domain type (CustomerName, CustomerId) instead of using their corresponding primitive type (string, int). In fsharp, with the help of Single-Case Discriminated Union, we can follow this guideline with minimal effort.

While following this practice in one of my recent project in fsharp, I came across a compelling use case, and I used a lesser-known approach to solve the problem. In this blog post, I will be sharing the method that I employed to address the use case.

## The Problem Domain

Let's assume that we are developing a F# Application for managing our expenses.

One of the core domain idea that we'll use a lot is **Money**.

In .NET, the primitive data type `decimal`

is appropriate for financial and monetary calculations.

Hence to model **Money** in fsharp, what we need is a Single Case Discriminated Union type wrapping the `decimal`

type.

`type Money = Money of decimal`

To keep things simple, we are not going to consider currency and exchange rates.

The next thing is modelling the income source and expense categories. For brevity, let's keep just two in each.

`type IncomeSource =`

| Salary

| Royalty

type ExpenseCategory =

| Food

| Entertainment

The final domain representation that we need is `Transaction`

, which is either a `Credit`

or a `Debit`

.

`type Income = {`

Amount : Money

Source : IncomeSource

}

type Expense = {

Amount : Money

Category : ExpenseCategory

}

type Transaction =

| Credit of Income

| Debit of Expense

For our small personal finance managing application, these domain models are just sufficient. So, let's dive into the use cases.

### Use Case #1

Our first use case is finding the expenditure on a given `ExpenseCategory`

from the list of the transaction

`ExpenseCategory -> Transaction list -> Money`

To implement it, let's create an intermediate function `getExpenses`

, that retrieves the expenses from a list of the transaction.

`// Transaction list -> Expense list`

let rec getExpenses transactions =

getExpenses' transactions []

and getExpenses' transactions expenses =

match transactions with

| [] -> expenses

| x :: xs ->

match x with

| Debit expense ->

getExpenses' xs (expense :: expenses)

| _ -> getExpenses' xs expenses

With the help of this `getExpenses`

function, we can now implement the use case as follows

`// ExpenseCategory -> Transaction list -> Money`

let getExpenditure expenseCategory transactions =

getExpenses transactions

|> List.filter (fun e -> e.Category = expenseCategory)

|> List.sumBy (fun expense ->

let (Money m) = expense.Amount // <1>

m // <2>

)

|> Money // <3>

<1> Unwrapping the underlying `decimal`

value from the `Money`

type.

<2> Returning the unwrapped decimal value.

<3> Putting the decimal value back to `Money`

type after computing the sum.

Now we have an implementation for use case #1 and let's move to the next.

### Use Case #2

The second use case is computing the average expenditure on a given `ExpenseCategory`

from the list of transactions

`// ExpenseCategory -> Transaction list list -> Money`

let averageExpenditure expenseCategory transactionsList =

transactionsList

|> List.map (getExpenditure expenseCategory)

|> List.map (fun (Money m) -> m) // <1>

|> List.average

|> Money // <2>

Like the use case #1,

<1> Unwraps the `decimal`

value from the `Money`

type and returns it.

<2> Put the result of the average function back to the `Money`

type.

### Use Case #3

Our final use case is from the list of transaction, we have to compute the balance money.

As we know, the formula for computing the balance is

`balance money = (sum of credited amount of money) - (sum of debited amount of money)`

Applying the same in fsharp, we will end up with the following implementation

`// Transaction list -> Money`

let balance transactions =

transactions

|> List.map ( function

| Credit x ->

let (Money m) = x.Amount // <1>

m

| Debit y ->

let (Money m) = y.Amount // <2>

-m

)

|> List.sum

|> Money // <3>

In the `balance`

function, we have used an optimised version of the formula.

Instead of computing the sum of credits and debits separately, we are applying the unary minus to all debits and calculating the sum of these transformed values in a single go.

Like what we did for the use cases #1 and #2, Here also we are unwrapping the `decimal`

type from the `Money`

type at <1> and <2>, and at <3> we are wrapping the `decimal`

type back to `Money`

type after computing the sum.

## Unwrapping and Wrapping Boilerplate

Though we have a good domain model in the form of `Money`

, a discouraging aspect is the repetition of unwrapping and wrapping code to perform calculations on the `Money`

type. We might be repeating the same for the future use cases as the `Money`

type is an integral part of the application.

Is there any way to get rid of this redundancy?

Yes, There is!

### List.sumBy function

The solution that we are looking for is lurking in the signature of the `List.sumBy`

function

`List.sumBy : ('T -> ^U) -> 'T list -> ^U`

(requires ^U with static member (+) and ^U with static member Zero)

The `sumBy`

function makes use of Statically resolved type parameters to define the the target type `^U`

(to be summed). As indicated in the signature, the type `^U`

should have two static members `+`

and `Zero`

.

In our case, the primitive type `decimal`

already has these static members, and the wrapper type `Money`

doesn't have it. Hence we are doing the wrapping and unwrapping!

Let's add these two static members in the `Money`

type

`type Money = Money of decimal with`

// Money * Money -> Money

static member (+) (Money m1, Money m2) = Money (m1 + m2) // <1>

static member Zero = Money 0m // <2>

<1> Unwraps the `decimal`

type for two operands of `Money`

and returns the summed value with the target type `Money`

<2> Returns the zeroth value of Money

We can now refactor the `getExpenditure`

function as

` let getExpenditure expenseCategory transactions =`

getExpenses transactions

|> List.filter (fun e -> e.Category = expenseCategory)

- |> List.sumBy (fun expense ->

- let (Money m) = expense.Amount

- m

- )

- |> Money

+ |> List.sumBy (fun expense -> expense.Amount)

### List.average function

Like the `List.sumBy`

function, the `List.average`

function has a requirement.

`// Signature`

List.average : ^T list -> ^T

(requires ^T with static member (+) and

^T with static member DivideByInt and

^T with static member Zero)

Out of these three requirements, we have already covered two (`+`

& `Zero`

) while accommodating the `List.sumBy`

function's requirement.

So, we just need to implement `DivideByInt`

static member in `Money`

to compute the average.

`type Money = // ...`

// ...

static member DivideByInt ((Money m), (x : int)) =

Decimal.Divide(m, Convert.ToDecimal(x))

|> Money

With this change, we can refactor `averageExpenditure`

as below

` let averageExpenditure expenseCategory transactionsList =`

transactionsList

|> List.map (getExpenditure expenseCategory)

- |> List.map (fun (Money m) -> m)

- |> List.average

- |> Money

+ |> List.average

### Unary Minus on Money Type

The final function that needs our help is the `balance`

function. To make the `unary minus`

work on `Money`

type, we can make use of operator overloading in fsharp.

`type Money = // ...`

// ...

static member (~-) (Money m1) = Money -m1

And then we can refactor the `balance`

function

` let balance transactions =`

transactions

- |> List.map ( function

- | Credit x ->

- let (Money m) = x.Amount // <1>

- m

- | Debit y ->

- let (Money m) = y.Amount // <2>

- -m

- )

- |> List.sum

- |> Money

+ |> List.map ( function

+ | Credit x -> x.Amount

+ | Debit y -> -y.Amount)

+ |> List.sum

## Summary

In this blog post, we saw how to avoid some boilerplate code while creating domain types for primitives in fsharp. On a side note, by adding the static members `+`

and `Zero`

we made the `Money`

type a Monoid. The `List.sum`

and `List.sumBy`

functions are designed to act on any Monoids and hence we solved the use cases with less code!

The source code is available on GitHub