[Haskell-cafe] Monad proof

harke at cs.pdx.edu harke at cs.pdx.edu
Mon Apr 14 19:52:45 EDT 2008


Here's part of a pencil-and-paper proof of laws for a state monad.

Before doing so, I've got a question of my own about the *other* laws:
Is there a place where somebody has explicitly written the laws that
"non-proper morphisms" of commonly used monads?

Back to the original question...

Beware.  What I'm about to say doesn't quite work in Haskell, for two
reasons.  First, you can't make my definition into an instance of the
class Monad without inserting type constructors into inconvenient places.
Second, due to the way undefined works in Haskell, the state monad
doesn't obey all the laws.

Assume we don't have non-termination, and assume we don't care about
overloading (>>=) and return (so we don't need to shoe-horn our monad
into the monad type class).

Preliminaries.  From the Prelude we have:
curry   :: ((a,b) -> c) -> a -> b -> c
uncurry :: (a -> b -> c) -> (a,b) -> c
id      :: a -> a

We define the state monad to be a synonym for a function returning a
pair:

M a = s -> (a,s)

Define morphisms

return  = curry id -- where id is specialized to type (a,s) -> (a,s)
m >>= k = (uncurry k) . m
get     = \s -> (s,s)
put s   = \_ -> ((),s)

Now check the laws.  Of the basic 3, I'll only do associativity.
The other 2 are easier.

Take the two sides of the conjectured law and unfold the definition
of >>= (and return), then use properties of uncurry (and curry) to
massage them into the same form.  If you can do so, the law holds.
(I'm going to avoid unfolding the definition of (un)curry so I can
stay at a higher level of abstraction, though the following might be
shorter if I did unfold them.)

LHS
== (p >>= q) >>= r
== uncurry r . (p >>= q)
== uncurry r . (uncurry q . p)

RHS =
== p >>= (\x -> q x >>= r)
== uncurry (\x -> q x >>= r) . p
== uncurry (\x -> uncurry r . q x) . p
== uncurry (\x s -> (uncurry r . q x) s) . p
== uncurry (\x s -> uncurry r (q x s)) . p
== (\xs -> uncurry r (q (fst xs) (snd xs))) . p
== (\xs -> uncurry r (uncurry q xs)) . p
== (\xs -> (uncurry r . uncurry q) xs) . p
== (uncurry r . uncurry q) . p

Now, one thing that's equally interesting (and perhaps not spoken of
often enough) is the laws that the "non-proper morphisms" obey.
In the case of state:

put a >> get == put a >> return a

  where each side reduces to \_ -> (a,a)

get >> get == get

  where each side reduces to \s -> ((),s)

BTW, in a proof assistant like Coq, Isabelle or Agda these identities
can be verified much more easily (though a badly done "proof script"
may be unreadable.)


On Fri, Apr 11, 2008 at 02:35:28PM -0300, Rafael C. de Almeida wrote:
> Hello,
>
> I was studying Monads and I was trying to think about new Monads I could  
> define. So, a question poped into my mind: how is proof regarding the 3 
> Monad laws handled? I know that, aside from testing all the possible values 
> (and there can be a lot of them), there's no general way to prove it. 
> Nonetheless, I think that it would be insightful to see how people write 
> those proofs for their monads -- specially for new user monads. Is there 
> some article or some notes on proving that Monads are implemented 
> correctly?
>
> []'s
> Rafael

-- 
Tom Harke
Portland State University


More information about the Haskell-Cafe mailing list