Re: Thinking about monads (Brent Yorgey)

You know, I was wondering... if Monads are a subset of Functors, and
Applicative is a subset of Functors, and Monads are a subset of
Applicative... shouldn't it be possible to tack on the definitions that
automatically derive Functor and Applicative? Isn't it the case that there
is really only one way to define Applicative for a Monad anyway? And isn't
there only one way to define fmap for a Monad that makes sense?
On Tue, Apr 14, 2009 at 2:39 PM,
Send Beginners mailing list submissions to beginners@haskell.org
To subscribe or unsubscribe via the World Wide Web, visit http://www.haskell.org/mailman/listinfo/beginners or, via email, send a message with subject or body 'help' to beginners-request@haskell.org
You can reach the person managing the list at beginners-owner@haskell.org
When replying, please edit your Subject line so it is more specific than "Re: Contents of Beginners digest..."
Today's Topics:
1. Re: Re: Thinking about monads (Brent Yorgey) 2. Re: How would you run a monad within another monad? (Arthur Chan) 3. Re: How would you run a monad within another monad? (Arthur Chan) 4. Re: How would you run a monad within another monad? (Arthur Chan) 5. Re: How would you run a monad within another monad? (Jason Dusek)
----------------------------------------------------------------------
Message: 1 Date: Tue, 14 Apr 2009 16:42:08 -0400 From: Brent Yorgey
Subject: Re: [Haskell-beginners] Re: Thinking about monads To: beginners@haskell.org Message-ID: <20090414204207.GA16671@seas.upenn.edu> Content-Type: text/plain; charset=us-ascii On Mon, Apr 13, 2009 at 03:11:42PM -0700, Michael Mossey wrote:
I know Maybe is both a functor and a monad, and I was thinking: what's
the
difference? They are both wrappers on types. Then I realized, the difference is: they have different class definitions.
In fact, every monad should be a functor, but not every functor is a monad. Being a monad is a much stronger condition than being a functor.
class Functor f where fmap :: (a->b) -> f a -> f b
(Note how fussy this definition would be in C++. It would be a kind of template, but would probably look a lot more complex and would require lengthy declarations.)
class Monad m where a >>= b :: m a -> (a -> m b) -> m b
Don't forget return :: a -> m a ! That's the other key method in the Monad class. (There are also >> and 'fail' but those are unimportant---the first is just a specialization of >>=, and fail is a hack).
-Brent
------------------------------
Message: 2 Date: Tue, 14 Apr 2009 14:05:22 -0700 From: Arthur Chan
Subject: Re: [Haskell-beginners] How would you run a monad within another monad? To: Jason Dusek Cc: beginners@haskell.org Message-ID: <74cabd9e0904141405i1fbadb85u8b87ffb05d61c493@mail.gmail.com> Content-Type: text/plain; charset="utf-8" Here's my contrived example that threw the error.
If you go into ghci, and do a `:t (foo' "blah" myDoohickey)`, you will get the type signature "IO ()". Doing the same for myOtherDoohickey returns "IO True"
So you would think that you'd be able to uncomment the code that makes IO an instance of Toplevel. foo' is a function that allows IO to run monadic values of type Doohickey. But it doesn't work.
---
import IO import Control.Monad.Reader
class (Monad n) => Doohickey n where putRecord :: String -> n ()
class (Monad m) => Toplevel m where foo :: (Doohickey n) => FilePath -> n a -> m a
newtype IOToplevelT a = IOToplevelT { runIOToplevelT :: ReaderT Handle IO a } deriving (Monad, MonadReader Handle, MonadIO)
instance Doohickey IOToplevelT where putRecord = liftIO . putStrLn
foo' s k = do f <- liftIO $ openFile s AppendMode runReaderT (runIOToplevelT k) f
--instance Toplevel IO where -- foo = foo'
myDoohickey = do putRecord "foo" putRecord "bar"
myOtherDoohickey = do putRecord "hello" putRecord "world" return True
On Mon, Apr 13, 2009 at 7:55 PM, Jason Dusek
wrote: Copypasting and loading your code doesn't throw an error. Please, pastebin an example that demonstrates the error.
-- Jason Dusek

On 15 Apr 2009, at 00:08, Arthur Chan wrote:
You know, I was wondering... if Monads are a subset of Functors, and Applicative is a subset of Functors, and Monads are a subset of Applicative... shouldn't it be possible to tack on the definitions that automatically derive Functor and Applicative? Isn't it the case that there is really only one way to define Applicative for a Monad anyway? And isn't there only one way to define fmap for a Monad that makes sense?
Yes, but at the same time no. Firstly, it's possible that you want an applicative instance that disagrees with your monad one – not common, and usually ugly, but possible. Secondly, it's often possible to implement the applicative/functor methods in a much more efficient way by dealing with them specifically. In reality, what we want to see is this: class Pointed f where pure :: a -> f a class Functor f where fmap :: (a -> b) -> f a -> f b class (Functor f, Pointed f) => Applicative f where (<*>) :: f (a -> b) -> f a -> f b class (Applicative f) => Monad f where join :: f (f a) -> f a Then we only need to define each behavior in one place, and the tree is neatly seperated out so that if we have something that isn't an Applicative, we can stop implementing after Functor, and if we have something that isn't a Monad, we can stop implementing after Applicative. Bob

On Tue, Apr 14, 2009 at 03:08:05PM -0700, Arthur Chan wrote:
You know, I was wondering... if Monads are a subset of Functors, and Applicative is a subset of Functors, and Monads are a subset of Applicative... shouldn't it be possible to tack on the definitions that automatically derive Functor and Applicative? Isn't it the case that there is really only one way to define Applicative for a Monad anyway? And isn't there only one way to define fmap for a Monad that makes sense?
Actually, it's already possible to do this, in a way. If you have a Monad, then fmap is liftM, pure is return, and (<*>) is ap. So you already have implementations of Functor and Applicative. In fact, I routinely do this: import Text.ParserCombinators.Parsec instance Applicative (GenParser tok st) where pure = return (<*>) = ap There are also various proposals which would help in automating this sort of process, like "class aliases". But in general, having a nicer class hierarchy as Bob suggests would be much better. -Brent
participants (3)
-
Arthur Chan
-
Brent Yorgey
-
Thomas Davie