>) instances of Monad and confusion about (

At different questions I've found hints in comments concerning using the (->) instance of Monads eg for realizing point-free style.

As for me, this is a little too abstract. Ok, I've seen Arrow instances on (->) and it seems to me, that (->) can be used in instance notations but not in type declarations (that would alone be stuff for another question).

Has anyone examples using (->) as instance of Monad? Or a good link?

Sorry if this question may already have been discussed here, but searching for " (->) Monad instance" gives you many many hits as you can imagine ... since nearly every question about Haskell somewhere involves (->) or "Monad".


For a given type r , the function of type r -> a can be thought of as a computation delivering an a using an environment typed r . Given two functions r -> a and a -> (r -> b) , it's easy to imagine that one can compose these when given an environment (again, of type r ).

But wait! That's exactly what monads are about!

So we can create an instance of Monad for (->) r that implements f >>= g by passing the r to both f and g . This is what the Monad instance for (->) r does.

To actually access the environment, you can use id :: r -> r , which you can now think of as a computation running in an environment r and delivering an r . To create local sub-environments, you can use the following:

inLocalEnvironment :: (r -> r) -> (r -> a) -> (r -> a)
inLocalEnvironment xform f = env -> f (xform env)

This pattern of having an environment passed to computations that can then query it and modify it locally is useful for not just the (->) r monad, which is why it is abstracted into the MonadReader class, using much more sensible names than what I've used here:

http://hackage.haskell.org/packages/archive/mtl/2.0.1.0/doc/html/Control-Monad-Reader-Class.html

Basically, it has two instances: (->) r that we've seen here, and ReaderT rm , which is just a newtype wrapper around r -> ma , so it's the same thing as the (->) r monad I've described here, except it delivers computations in some other, transformed monad.


To define a monad for (->) r , we need two operations, return and (>>=) , subject to three laws:

instance Monad ((->) r) where

If we look at the signature of return for (->) r

    return :: a -> r -> a

we can see its just the constant function, which ignores its second argument.

    return a r = a

Or alternately,

    return = const

To build (>>=) , if we specialize its type signature with the monad (->) r ,

    (>>=) :: (r -> a) -> (a -> r -> b) -> r -> b

there is really only one possible definition.

    (>>=) x y z = y (x z) z

Using this monad is like passing along an extra argument r to every function. You might use this for configuration, or to pass options way down deep into the bowels of your program.

We can check that it is a monad, by verifying the three monad laws:

1. return a >>= f = f a 

return a >>= f 
= (b -> a) >>= f -- by definition of return
= (x y z -> y (x z) z) (b -> a) f -- by definition of (>>=)
= (y z -> y ((b -> a) z) z) f -- beta reduction
= (z -> f ((b -> a) z) z) -- beta reduction
= (z -> f a z) -- beta reduction
= f a -- eta reduction

2. m >>= return = m

m >>= return
= (x y z -> y (x z) z) m return -- definition of (>>=)
= (y z -> y (m z) z) return -- beta reduction
= (z -> return (m z) z) -- beta reduction
= (z -> const (m z) z) -- definition of return
= (z -> m z) -- definition of const
= m -- eta reduction

The final monad law:

3. (m >>= f) >>= g  ≡  m >>= (x -> f x >>= g)

follows by similar, easy equational reasoning.

We can define a number of other classes for ((->) r) as well, such as Functor,

instance Functor ((->) r) where

and if we look at the signature of

   -- fmap :: (a -> b) -> (r -> a) -> r -> b

we can see that its just composition!

   fmap = (.)

Similarly we can make an instance of Applicative

instance Applicative ((->) r) where
   -- pure :: a -> r -> a
   pure = const

   -- (<*>) :: (r -> a -> b) -> (r -> a) -> r -> b
   (<*>) g f r = g r (f r)

What is nice about having these instances is they let you employ all of the Monad and Applicative combinators when manipulating functions.

There are plenty of instances of classes involving (->), for instance, you could hand-write the instance of Monoid for (b -> a), given a Monoid on a as:

enter code here
instance Monoid a => Monoid (b -> a) where
    -- mempty :: Monoid a => b -> a
    mempty _ = mempty
    -- mappend :: Monoid a => (b -> a) -> (b -> a) -> b -> a
    mappend f g b = f b `mappend` g b

but given the Monad/Applicative instance, you can also define this instance with

instance Monoid a => Monoid (r -> a) where
    mempty = pure mempty
    mappend = liftA2 mappend

using the Applicative instance for (->) r or with

instance Monoid a => Monoid (r -> a) where
    mempty = return mempty
    mappend = liftM2 mappend

using the Monad instance for (->) r .

Here the savings are minimal, but, for instance the @pl tool for generating point-free code, which is provided by lambdabot on the #haskell IRC channel abuses these instances quite a bit.

链接地址: http://www.djcxy.com/p/47692.html

上一篇: 将语义应用于免费Monad

下一篇: >)Monad的实例和混淆(