M*****

Technical, Functional programming## title: M***** title_hover: Monads created_at: 2020-12-28T14:52:16.823Z updated_at: 2020-12-28T14:52:16.823Z tldr: The not so dreadful m-word in programming is_published: 1 star: true category: Technical, Functional programming share_type: share

Forgetting the math behind what monad is, let's take a bird's eye look at how it works.

Monads are simple.

Monads are software design patterns that allow a user to chain operations, while the monad changes secret work behind the scenes.

Let's travel this land from no monad pattern to a monad pattern

Let's say we have a banking requirement

```
function debitUserAccount(currentSaving: number, amount: number): number {
const newSavings = currentSaving - amount;
return newSavings;
}
function creditUserAccount(currentSaving: number, amount: number): number {
const newSavings = currentSaving + amount;
return newSavings;
}
// we call it by
debitUserAccount(100, 1);
// we can chain it like
debitUserAccount(creditUserAccount(99, 1), 1);
```

now say we need to add logs every time a transaction is made

```
interface Savings {
current: number;
logs: string[];
}
function debitUserAccount(currentSaving: number, amount: number): Savings {
const newSavings = currentSaving - amount;
return {
current: newSavings,
logs: [`${amount} was debited, new savings: ${newSavings}`],
};
}
function creditUserAccount(currentSaving: number, amount: number): Savings {
const newSavings = currentSaving + amount;
return {
current: newSavings,
logs: [`${amount} was credited, new savings: ${newSavings}`],
};
}
// now we cant chain these functions
debitUserAccount(creditUserAccount(99, 1), 1);
```

`debitUserAccount`

function needs a number but `creditUserAccount`

returns a `Savings`

interface.

```
function debitUserAccount(savings: Savings, amount: number): Savings {
const newSavings = savings.current - amount;
return {
current: newSavings,
logs: savings.logs.push([
`${amount} was debited, new savings: ${newSavings}`,
]),
};
}
function creditUserAccount(savings: Savings, amount: number): Savings {
const newSavings = savings.current + amount;
return {
current: newSavings,
logs: savings.logs.push([
`${amount} was credited, new savings: ${newSavings}`,
]),
};
}
// to get to a savings type we need to create a savings wrapper
// it just wraps the plain amount to `Savings` type
function createSavings(amount: number): Savings {
return {
current: amount,
logs: [],
};
}
// so now we can chain this in any order
debitUserAccount(creditUserAccount(createSavings(99), 1), 1);
```

In the above functions we just created a wrapper functions for `savings`

and created 2 operations functions which can be called on `savings`

in any order which returns a `savings`

type

There seems to be a duplicated logic of addigns logs, lets refactor this so that we can run the operation logic for the `savings`

.

```
function applyTransactions(
savings: Savings,
transaction: (amount: number) => () => Savings,
): Savings {
const newTransaction = transaction(savings.current);
return {
current: newTransaction.current,
logs: [...savings.logs, ...newTransaction.logs],
};
}
// and we rewrite debit and credit function as
function debitUserAccount(amount: number): Savings {
return (savings: numbers) => {
return {
current: savings - amount,
logs: [`${amount} was debited, new savings: ${newSavings}`],
};
};
}
function creditUserAccount(amount: number): Savings {
return (savings: number) => {
return {
current: savings + amount,
logs: [`${amount} was credited, new savings: ${newSavings}`],
};
};
}
```

oh nice, now debit and credit don't need to do append logs anymore, they are independent functions on their own. And they don't need a `savings`

type anymore they just need the amount to do the transaction.

Now we can do indipendent transactions in any order we want to

```
const savings = createSavings(99);
const d1 = applyTransactions(savings, debitUserAccount(1));
const c1 = applyTransactions(d1, creditUserAccount(1));
...
// we can also add new transactions without log concatination logic
const i1 = applyTransactions(d1, creditInterest(0.7));
```

well this is a `Monad`

, Tada ðŸŽ‰. Monads at thier core are helpful design patterns. We just built one. They allow to chain operations, managing busy work behind the scene.

All monads have 3 components

```
> Wrapper type: Savings
> Wrapper function: createSavings
// they are help take a non monadic thing and wrap to a monadic world
// like a constructor
> Runner: applyTransactions
// they take objects in the monadic world and apply transformation on them
```

well this is just an introduction to how monad patterns can be incredibly useful in designing applications. There are may more of wonders in mondads like `options`

, `lists`

, `compose`

, `promise`

...

I hope this made monads little more approchable...

### Further reading

Like it ?

Share with friends