Use tee and carry on

Originally, this blogpost was titled “Use apply and carry on”, but I guess naming the function apply after Kotlin (damn you, Kotlin!) wasn’t the most preferred option by the public. I did like apple |> apply eat semantics but if Scott Wlaschin says apply is a different thing then it is a different thing. To be precise Scott’s is apply: (a -> b) -> a -> b and mine was (emphasize on was) apply: (a -> unit) -> a -> a. Apparently, the function which does whatever I wanted apply to do is called tee (after Unix command) or tap (at least in Ruby and Ramda.js).

So I’ve edited it and replaced apply with tee, but essentially it is almost unchanged… Let’s go then.


One of everyone’s favourite features of F# is pipe (|>) operator. It allows to pipe output of one function as input to another function preserving visual honesty. The general idea is that, in English, we read left-to-right and top-down. In C# (C, C++, Java, Pascal, Python) we read in all possible directions, most likely top-down for overall structure but botton-up and right-to-left for single statements.

Visual honesty

For example:

1
var y = Math.Round(Math.Exp(Math.Sin(x*5.2 + 7.1)));

starts at the right end going left-to-right for a moment (x*5.2 + 7.1) but then turns right-to-left with Math.Sin, Math.Exp and finally Math.Round (in this order). In F# the pipe operator (|>) allows to write code exactly in the same order as it is going to be executed:

1
let y = x*5.2 + 7.1 |> Math.Sin |> Math.Exp |> Math.Round

Around the world, many hours have been spent arranging function arguments (guilty!) to allow such seamless experience. But sometimes, the universe is against us. Let’s assume we would like to print out the value after Math.Sin. The conservative approach would be quite intrusive - we would need to break expression in half:

1
2
3
let temp = x*5.2 + 7.1 |> Math.Sin
printf "%g" temp
let y = temp |> Math.Exp |> Math.Round

Whoa! That is intrusive.

But here comes the rescue. The tee function implemented as:

1
let tee func arg = func arg; arg

The function itself is trivial, it takes a function and an argument, executes given function with given argument but then returns it, so the argument goes through the function:

1
let y = x*5.2 + 7.1 |> Math.Sin |> tee (printf "%g") |> Math.Exp |> Math.Round

In the example above, the value passed between Math.Sin and Math.Exp has been redirected “for a moment” to printf "%g" without any temporary variables or breaking the flow.

Recently I needed to shuffle an array. The algorithm I used shuffles array in place:

1
2
3
4
5
6
7
8
let inline swapInPlace i j (array: 'a[]) =
let t = array.[i]
array.[i] <- array.[j]
array.[j] <- t
let shuffleInPlace (array: 'a[]) =
for i = array.Length - 1 downto 1 do
array |> swapInPlace i (Random.randomInt 0 i)

(Random.randomInt is not a standard function, but its implementation is irrelevant for this example)

I needed it as pure function, which will not mutate input array, just return shuffled version of it. Let’s do it:

1
2
3
4
let shuffle array =
let result = Array.copy array
shuffleInPlace result
result

Maybe we can do better with tee? Yes, we can:

1
let shuffle array = array |> Array.copy |> tee shuffleInPlace

Much better.

So, use tee and carry on!