Named things in Haskell
For my GSoC project, I have to deal with named things, and I tried to generalized the traditional (String,a)
object and I came with an interesting Named a
data.
The problem
We often deal with named things, on which we want to perform some operations, without changing its name. For example, I want to benchmark libraries, so I will start with something like (String, Benchmark)
, the String
being the library name, and come out to a (String, Double)
, with the Double
being the time of taken by the function.
( For the sake of simplicity, lets imagine we have a function:
)
The Named Data
I started to write the Named
data:
and one needed instance:
And then, the main idea: applying a function f: a -> b
to a Named a
will produce a Named b
without changing the name. My Haskell alarms ringed and detected a Functor
instance:
Well, so thought I was able to write a pretty function like:
But recall, bench
is of type Benchmark -> IO Double
, so, using only fmap
will lead to:
So…
The Traversable instance
The solution is to provide sequence :: Monad m => Named (m a) -> m (Named a)
, which is inside the Traversable
class. As its type says, sequence
will “strip-out” the monadic effect. So we have:
And poof, I am able to write:
Because this is a common thing to do, we can use a classic function, traverse
, and hence:
Hooray ! But can we do better ? Named
seems a pretty interesting object…
Is Named a Monad ? (Answer, no it is a CoMonad)
An interesting Functor
is sometimes a Monad
. So I started my checklist: to provide a Monad
I have to provide the return
and the bind
function:
I don’t have a standard way to name things, and neither to get a name out of two named things… But I can easily strip out the name, and conserve the name:
It seems pretty much like something dual to a monad. And this is called a Comonad
:)
The instance definition:
Well we have a Comonad instance, we can redefine the Eq
instance, given a little function:
liftExtract
can in fact be used to define every lifted instances of transformers…
And can even redefine the Functor
instance: