I love finding neat little bits of Haskell that do things in ways I haven’t really thought of before. This usually happens when I come across a simple yet slightly clumsy way of doing something, and embark on some mad experiments to find alternative approaches (usually ending in a trip to #haskell.au on Freenode). These alternatives may not result in anything usable, but they often prove to be fun learning experiences for me.
A recent example of this was the following adventure in passing the same input to two functions, and getting the output as a tuple.
The boring way
Here we’ve piped the input through the +1
function to get the first part of the tuple, and through the show
function for the second. We can generalise this to work with any two functions:
Combining arrows
It turns out stillBoring
is already provided in Haskell, albeit in a an awesomely unboring way. This is the type of the &&&
operator from Control.Arrow
:
(&&&) :: Arrow a => a b c -> a b c' -> a b (c, c')
I struggled to see the connection between this and the stillBoring
type signature, until it was pointed out that the a
in this particular case is function application (->)
. If we substitute this in it begins to look more like what I’m used to seeing:
This is what we needed, to take two functions that both take the same type, and turn it into a function that takes a single input and returns each function’s output as a tuple (b -> (c, c')
).
Super-unboring two argument functions
We’ve been dealing with single argument functions a -> b
so far. What if we have functions that take two arguments, a -> b -> c
, and we want to get a tuple from those?1
So now, given two two-argument functions, we get a new function that takes two arguments, feeds each of those to the original functions, and puts the output from one in the first tuple position, and the output from the other in the second position.
Mad Haskell meets practical application
This experiment actually started while writing a function to find list duplicates for Tony Morris’ State exercise (feel free to join in).
Given an item x
from a list, we had to produce a State
that calculated whether the item was a member of the Data.Set
from the previous state, and the new state with x
added to the Data.Set
. The full context is on GitHub, but the relevant snippets are below:
State
is just one common case where we need to produce tuples, and now we have a few (possibly slightly mad) ways to compose functions to get us them.
This
liftA2 (&&&)
solution provided courtesy of Tony Morris on #haskell.au on Freenode.↩