Derek Elkins ddarius at hotpop.com
Thu Oct 2 09:08:16 EDT 2003

```On Thu, 02 Oct 2003 12:59:25 +0200
Juanma Barranquero <jmbarranquero at laley.wke.es> wrote:

> On Thu, 02 Oct 2003 11:22:13 +0200
> "Marcin 'Qrczak' Kowalczyk" <qrczak at knm.org.pl> wrote:
>
> > As you discovered, there is no meaningful count of operations. If an
> > operation doesn't do anything, do you count it?

The Count monad with return defined as Count 0 a with >>= adding them is
It's also a potentially useful monad.  I've seen the equivalent called
the Complexity monad before.  Using that intuition, return a is
something that has 0 complexity.  What you needed to do was add
primitives that have a complexity you want to measure.  For example if
you were considering space complexity, you might have a cons primitive
defined as say, cons x xs = Count 2 (x:xs), but multiplication, say,
would have zero complexity.  In general you could use a HOF to add
complexity annotations to functions or add a bump = Count 1 () to bump
up the complexity of some computation,
cons x xs = bump >> bump >> return (x:xs)

> It's not about counting the operations (that's just an example), but
> accumulating any kind of state.

This isn't state, this is, again, a (broken) instance of the
Writer/Output monad.  The return should use the empty list and your >>=
doesn't even make sense.

> For example:
>
>   data Accum a = Ac [a] a
>
>       return x     = Ac [x] x
>       Ac _ x >>= f = let Ac l x' = f x in Ac (l ++ [x']) x'
>
>   dupAcc x = Ac [x,x] x
>
>   m1 = (return 'a') >>= dupAcc   -- Ac "aaa" 'a'
>   m2 = dupAcc 'a'                -- Ac "aa"  'a'

Which shows that your monad is broken.  As Markus mentions, -you- have
don't hold, you don't have a monad.

> > but monad laws say that "return" *really* doesn't do anything
>
> I don't see it. As I understand, the problem (if any) would be in my
> implementations of either >>= or f (dupAcc, in this case). I get the
> same values for m1 and m2 even if I define return x = Ac [] x.

As Marcin said, return doesn't do anything.  In fact, I believe
the monad laws together effectively state that both >>= and return are
"pure" with respect to whatever computation is being modelled.  So the
associativity condition says that it doesn't matter which >>= is
evaluated first.

Another thing that should be noted, is that most monads are completely
useless without "primitive" computations.  I.e. using only >>= and
return will get you nothing that couldn't have been done "purely".  This
can be seen by considering the similarity between monads and monoids.
return corresponds to the neutral element of a monoid, while join m = m
>>= id is the multiplication.  One example of a monoid is the
natural numbers with 0 as the neutral element and + as the
multiplication.  If we only use 0 and + the result is rather boring,
0+0+0+0, 0+0.  This is similar to only using return and >>=.  If we use
other elements (corresponding to primitive monadic computations) things
are much more interesting, 4+90+0+2, 10+3.

So again, with Accum, you need a "primitive" computation that actually
is effectful while return and >>= aren't, with the Writer monad this is
tell :: [a] -> Writer() which is similar to putStr except it doesn't
perform IO, it just collects up a list of "output".

> I'm not trying to create useful monads (I'm pretty sure they aren't
> :), but understanding the concepts. So, the question remains: when the
>
>   (return x) >>= f == f x
>
> what is intended in that "=="? Eq."==" for
>
>   instance Eq MyCustomMonad where x == y = whatever...
>
> or a more profound kind of equality?

A more profound kind, as it usually isn't possible to define a
reasonable instance of Eq for monads.  Anyways, these laws are the ones
from the Category Theory definition of monads (slightly restructured),