# Functor-Applicative-Monad Proposal

### From HaskellWiki

(Difference between revisions)

(fail in MonadPlus) |
(MonadFail) |
||

Line 17: | Line 17: | ||

join :: m (m a) -> m a |
join :: m (m a) -> m a |
||

join x = x >>= id |
join x = x >>= id |
||

+ | |||

+ | class Monad m => MonadFail m where |
||

+ | fail :: String -> m a |
||

</haskell> |
</haskell> |
||

This would eliminate the necessity of declaring a Monad instance for every Applicative, and eliminate the need for sets of duplicate functions such as [<hask>fmap</hask>, <hask>liftM</hask>, <hask>map</hask>, <hask>liftA</hask>], [<hask>(<*>)</hask>, <hask>ap</hask>], and [<hask>concat</hask>, <hask>join</hask>]. |
This would eliminate the necessity of declaring a Monad instance for every Applicative, and eliminate the need for sets of duplicate functions such as [<hask>fmap</hask>, <hask>liftM</hask>, <hask>map</hask>, <hask>liftA</hask>], [<hask>(<*>)</hask>, <hask>ap</hask>], and [<hask>concat</hask>, <hask>join</hask>]. |
||

− | <hask>fail</hask> should be removed from Monad; a failed pattern match should error in the same way as is does for pure code, while in <hask>MonadPlus</hask>, the current behaviour could be maintained with <hask>mzero</hask>. This would, however, complicate the Monad machinery. |
+ | A monad which requires custom handling for pattern match failures can implement <hask>MonadFail</hask>; otherwise, a failed pattern match will error in the same way as is does for pure code. |

<hask>Pointed</hask> has not been included due to controversy as to whether it should be a subclass of Functor, a superclass of Functor, independent of Functor, or perhaps it is not sufficiently useful to include at all. |
<hask>Pointed</hask> has not been included due to controversy as to whether it should be a subclass of Functor, a superclass of Functor, independent of Functor, or perhaps it is not sufficiently useful to include at all. |

## Revision as of 16:06, 21 December 2010

The standard class hierarchy is a consequence of Haskell's historical development, rather than logic. TheFunctor

Applicative

Monad

class Functor f where map :: (a -> b) -> f a -> f b class Functor f => Applicative f where return :: a -> f a (<*>) :: f (a -> b) -> f a -> f b (*>) :: f a -> f b -> f b (<*) :: f a -> f b -> f a class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b f >>= x = join $ map f x join :: m (m a) -> m a join x = x >>= id class Monad m => MonadFail m where fail :: String -> m a

fmap

liftM

map

liftA

(<*>)

ap

concat

join

MonadFail

Pointed

Backward compatibility could be eased with a legacy module, such as:

module Legacy where fmap :: Functor f => (a -> b) -> f a -> f b fmap = map liftA :: Applicative f => (a -> b) -> f a -> f b liftA = map liftM :: Monad m => (a -> b) -> m a -> m b liftM = map ap :: Monad m => m (a -> b) -> m a -> m b ap = (<*>) (>>) :: Monad m => m a -> m b -> m b (>>) = (*>) concat :: [[a]] -> [a] concat = join etc.

And for those who really want a list map,

listMap :: (a -> b) -> [a] -> [b] listMap = map

Context alias would also be a great help with backwards compatibility.

Another variant might be to split aPointed

Applicative

class Pointed f where return :: a -> f a class (Functor f, Pointed f) => Applicative f where (<*>) :: f (a -> b) -> f a -> f b (*>) :: f a -> f b -> f b (<*) :: f a -> f b -> f a

Pointed