- Published on

# Refactor Any Curried Function with Only Two Basic Functions in Typescript (or Any Language)

Suppose you have a curried function that takes four arguments, for example:

```
const getPaymentAmount =
(price: number) =>
(quantity: number) =>
(discount: number) =>
(taxRate: number): number =>
(price * quantity - discount) * (1 + taxRate)
assert.deepStrictEqual(getPaymentAmount(10)(2)(5)(0.2), 18)
```

Often, a programmer would want to extend this `getPaymentAmount`

function *without modifying* it. For example, one may want to produce a new function:

**with a fixed discount**: by moving the third argument`discount`

to the top level, so one can partially apply it away; or**that accepts an argument of another type**: by changing the type of the fourth argument`taxRate`

from`number`

to`string`

.

A naive way would be to wrap around the function with a new function like so:

```
const getPaymentAmountWrapped =
(/* moved to top level */ discount: number) =>
(price: number) =>
(quantity: number) =>
(taxRate: /* changed from number to */ string) =>
getPaymentAmount(price)(quantity)(discount)(parseFloat(taxRate))
const getPaymentAmountNoDiscount = getPaymentAmountWrapped(0)
assert.deepStrictEqual(getPaymentAmountNoDiscount(10)(2)('0.2'), 24)
```

Though it works, the code is very redundant. The programmer has to repeat the same boilerplate wrapping everytime in similar situations.

Is there a way to refactor and/or extend *any* curried function in a generic, concise, and mechanical way?

The answer is yes.

*You can find all the code in this post and play around with them at Typescript Playground.*

`compose`

and `flip`

Let's quickly go over two basic and commonly used functions in functional programming languages such as Haskell.

`compose`

`compose`

combines two functions and outputs a new one.

If you have a function `f :: b -> c`

and a function `g :: a -> b`

, then you can get a new function `h :: a -> c`

by composing `f`

and `g`

.

In Haskell, it is written tersely as:

```
compose :: (b -> c) -> (a -> b) -> a -> c
compose f g = \x -> f (g x)
```

In Typescript, it looks a bit more verbose:

```
const compose =
<B, C>(f: (b: B) => C) =>
<A>(g: (a: A) => B) =>
(a: A): C =>
f(g(a))
const f = (x: number): string => x.toString()
const g = (b: boolean): number => (b ? 1 : 0)
const h: (b: boolean) => string = compose(f)(g)
assert.deepStrictEqual(h(true), '1')
```

`flip`

`flip`

swaps the first argument and the second argument of a function:

```
flip :: (a -> b -> c) -> b -> a -> c
flip f a b = f b a
```

In Typescript :-

```
const flip =
<A, B, C>(f: (a: A) => (b: B) => C) =>
(b: B) =>
(a: A) =>
f(a)(b)
const concat = (x: string) => (y: string) => x + y
assert.deepStrictEqual(flip(concat)('left')('right'), 'rightleft')
```

## Swap Any Arguments at Any Level

Here comes the fun part.

If we want to swap the first and the second arguments of any function, we can apply `flip`

:-

```
const _1234 = (_1: string) => (_2: string) => (_3: string) => (_4: string) => _1 + _2 + _3 + _4
const _2134 = flip(_1234)
assert.deepStrictEqual(_2134('2')('1')('3')('4'), '1234')
```

But what if we want to swap the second `_2`

and the third `_3`

arguments? We will need to apply `flip`

to the *result* of the outermost function.

### Semantic Editor Combinators

Semantic editor combinators ("**SEC**") is a term coined by Conal Elliot. It describes an alternative way to interpret, *inter alia*, `compose`

and `flip`

.

The `compose`

function, under the lens of **SEC**, has the effect of getting the *result* out of a function, when viewing `compose`

as *unary* instead of *binary*.

The best way to gain some intuitions is to see its effects.

First, let's rename `compose`

with a more intuitive label:

```
const result = compose
```

Then, to swap the second `_2`

and the third `_3`

arguments, we can compose `flip`

with `result`

:-

```
const flip2_3: Flip2_3 = result(flip)
const _1324 = flip2_3(_1234)
assert.deepStrictEqual(_1324('1')('3')('2')('4'), '1234')
```

*Note: For readability, I omitted some typings from the code snippets. You can find them in the Typescript Playground link above.*

Note that we need to spell out the type `Flip2_3`

for Typescript. This is because, unfortunately, Typescript's type system could not infer the type for us (vs Haskell, which does).

One naturally wonders if the third argument `_3`

and the fourth argument `_4`

could similarly be swapped. Indeed we can, we just need to apply `result`

one more time!

```
const flip3_4: Flip3_4 = result(result(flip))
const _1243 = flip3_4(_1234)
assert.deepStrictEqual(_1243('1')('2')('4')('3'), '1234')
```

In fact, you can go crazy and create functions that swap arguments at arbitrarily deep nested level:

```
const flip6_7: Flip6_7 = result(result(result(result(result(flip)))))
```

One can easily build an arsenal of these functions and export them as a library.

### Application

Back to our original example: to move the argument `discount`

to the top, we can do so mechanically:

```
const _getPaymentAmount = flip(flip2_3(getPaymentAmount))
const _getPaymentAmountNoDiscount = _getPaymentAmount(0)
assert.deepStrictEqual(_getPaymentAmountNoDiscount(10)(2)(0.2), 24)
```

## Alter any arguments at any level

Let's take a step further.

Instead of swapping arguments, what if we want to *alter* the arguments? In our example above, we want to convert `taxRate`

from `string`

to `number`

before feeding it to the `getPaymentAmount`

function.

First, note that if we apply `flip`

to `compose`

, the result is `precompose`

:-

```
precompose :: (a -> b) -> (b -> c) -> a -> c
precompose = flip compose
```

In Typescript :-

```
const precompose = flip(compose) as Precompose
```

As a dual with `result`

a.k.a `compose`

, we can think of `precompose`

as returning the`arguments`

```
const argumnts = precompose
```

Again we can create arbitrarily deep level as we want:

```
const argumnts2: Argumnts2 = (x) => result(argumnts(x))
const argumnts4: Argumnts4 = (x) => result(result(result(argumnts(x))))
const sum4 = (a: number) => (b: number) => (c: number) => (d: number) => a + b + c + d
const sum4WithString = argumnts4(parseInt)(sum4)
assert.deepStrictEqual(sum4WithString(1)(2)(3)('4'), 10)
```

Note that we changed the fourth argument of the `sum4`

function from `number`

to `string`

by just precomposing with `parseInt`

!

## Application

Ok, back to our initial example. The application is mechanical :-

```
const _getPaymentAmountWithString = argumnts4(parseFloat)(getPaymentAmount)
assert.deepStrictEqual(_getPaymentAmountWithString(10)(2)(5)('0.2'), 18)
```

The fourth argument `taxRate`

now takes a `string`

instead of a `number`

, as promised.

## Conclusion

We covered a lot of grounds.

With two basic functions `compose`

and `flip`

, we can generate a bunch of functions that swap and/or alter arguments at any level, for any curried function. In addition, this approach comes with the following benefits:

**Purely functional**: this means that it comes with all the benefits of FP: referential transparency, testability, conciseness, etc.**Generic & mechanical**: as mentioned above, one could write a bunch of these functions and export them as a library. Then, it can be applied anywhere.**Universal**: finally, since the underlying mechanics is "just maths", it is applicable to any programming languages, not just Typescript.