Open The Tap to Functional Logging
After throwing ourselves into a functional approach to programming, using function composition, smart datatypes and curried pure functions, we often find that our programs "just work" much more frequently than ever before.
Sadly not always.
Invariably we come across a situation when our code does not work as expected and we have to debug this:
const doSomeMathsStuff = compose(
add(5),
multiplyBy(12),
divideBy(4),
subtract(2)
);
doSomeMathsStuff(2);
This looks a bit like a closed box - we can give an input and get an output, but never inspect the internal workings. Fortunately we can use a simple function - the tap, or K-combinator - to inspect our data as it moves through the composed functions.
The idea is simple - the tap function will take an input, pass it to another function (such as console.log
), then return the input unchanged. Using TypeScript to define the signature we would get:
type Tap<T> = (fn: (a: T) => void) => (x: T) => T;
We can implement it relatively easily:
const tap = fn => x => {
fn(x);
return x;
}
We can now use it within our compose function to inspect data as it moves between functions:
const doSomeMathsStuff = compose(
add(5),
tap(console.log),
multiplyBy(12),
tap(console.log),
divideBy(4),
tap(console.log),
subtract(2),
tap(console.log)
);
doSomeMathsStuff(2);
// Logs:
// 7
// 84
// 19
This returns to us the power of simple debugging. Functional combinators are an interesting topic, and one that I'll probably return to in the near future.