Stylistically this is very nice. In the real world, I would expect a 60% chance of this notation instead of the one you gave:
C x c >>= f = C (value $ f x) (c + 1)
But that is so minor it is hardly worth mentioning.
On a more serious note, not stylistic but semantic: this is not a monad. In fact, it violates all three of the monad laws.
(1) return x >>= f = f x
(2) m >>= return = m
(3) m >>= (f >=> g) = (m >>= f) >>= g
(Where (>=>)
is defined as f >=> g = x -> f x >>= g
. If (>>=)
is considered an "application" operator, then (>=>)
is the corresponding composition operator. I like to state the third law using this operator because it brings out the third law's meaning: associativity.)
With these computations:
(1):
return 0 >>= return
= C 0 0 >>= return
= C (value $ return 0) 1
= C 0 1
Not equal to return 0 = C 0 0
(2):
C 0 0 >>= return
= C (value $ return 0) 1
= C 0 1
Not equal to C 0 0
(3)
C 0 0 >>= (return >=> return)
= C (value $ (return >=> return) 0) 1
= C (value $ return 0 >>= return) 1
= C (value $ C 0 1) 1
= C 0 1
Is not equal to:
(C 0 0 >>= return) >>= return
= C (value $ return 0) 1 >>= return
= C 0 1 >>= return
= C (value $ return 0) 2
= C 0 2
This isn't just an error in your implementation -- there is no monad that "counts the number of binds". It must violate laws (1) and (2). The fact that yours violates law (3) is an implementation error, however.
The trouble is that f
in the definition of (>>=)
might return an action that has more than one bind, and you are ignoring that. You need to add the number of binds from the left and right arguments:
C x c >>= f = C y (c+c'+1)
where
C y c' = f x
This will correctly count the number of binds, and will satisfy the third law, which is the associativity law. It won't satisfy the other two. However, if you drop the +1
from this definition, then you do get a real monad, which is equivalent to the Writer
monad over the +
monoid. This basically adds together the results of all subcomputations. You could use this to count the number of somethings, just not binds -- bind is too special to count. But, for example:
tick :: C ()
tick = C () 1
Then C
will count the number of tick
s that occurred in the computation.
In fact, you can replace Int
with any type and (+)
with any associative operator and get a monad. This is what a Writer
monad is in general. If the operator is not associative, then this will fail the third law (can you see why?).