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:
It turns out
stillBoring is already provided in Haskell, albeit in a an awesomely unboring way. This is the type of the
&&& operator from
(&&&) :: 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
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.