# Functor-Applicative-Monad Proposal

### From HaskellWiki

(Difference between revisions)

(GHC Proposal) |
Lambda Fairy (Talk | contribs) (Rewrite the page!) |
||

Line 1: | Line 1: | ||

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

− | + | This article attempts to document various suggestions that have been brought up over the years, along with arguments for and against. | |

− | + | ||

− | + | ||

− | + | == Make <hask>Applicative</hask> a superclass of <hask>Monad</hask> == | |

− | + | ||

− | + | ||

− | + | ||

− | + | ||

+ | <haskell> | ||

class Applicative m => Monad m where | class Applicative m => Monad m where | ||

− | + | ... | |

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

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

− | + | === For === | |

− | + | * Code that is polymorphic over the Monad can use Applicative operators rather than the ugly <hask>liftM</hask> and <hask>ap</hask>. | |

− | + | * Most types that implement Monad also implement Applicative already. This change will only make explicit a current best practice. | |

− | + | === Against === | |

− | + | * Monad is part of standard Haskell, but Applicative is not. If Monad is made a subclass of Applicative, then we will need to add Applicative to the language standard. | |

− | + | ||

− | + | * Some libraries, such as [http://hackage.haskell.org/packages/archive/blaze-markup/0.5.1.5/doc/html/Text-Blaze-Internal.html#t:MarkupM blaze-markup], only implement Monad for its do-notation. For these types, an Applicative instance would have no meaning. | |

− | + | ||

− | + | == Add <hask>join</hask> as a method of <hask>Monad</hask> == | |

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

<haskell> | <haskell> | ||

− | + | class Applicative m => Monad m where | |

− | + | (>>=) :: (a -> m b) -> m a -> m b | |

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

+ | ... | ||

+ | m >>= k = join (fmap k m) | ||

+ | join m = m >>= id | ||

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

− | + | === For === | |

− | + | * <hask>fmap</hask>/<hask>join</hask> is more orthogonal than <hask>fmap</hask>/<hask>>>=</hask>, and the former is closer to the categorical definition. | |

− | < | + | * <hask>join</hask> is often easier to implement. See [http://article.gmane.org/gmane.comp.lang.haskell.libraries/14926]. |

− | + | ||

− | + | ||

− | + | * The analogous [http://hackage.haskell.org/packages/archive/comonad/3.0.2/doc/html/Control-Comonad.html comonad] package is written this way. | |

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | === Against === | |

− | = | + | * <hask>>>=</hask> is used much more frequently in real-world code than <hask>join</hask>. |

− | + | ||

− | + | * Performance: The default implementation of <hask>>>=</hask> requires two traversals. Any container-like type which only implements <hask>fmap</hask> and <hask>join</hask> would be slower. | |

− | + | == Remove <hask>liftM</hask>, <hask>ap</hask>, etc. in favor of their Applicative counterparts == | |

− | + | === For === | |

− | + | ||

− | + | ||

− | + | ||

− | + | * We will end up with a simpler base library. | |

− | + | ||

− | + | === Against === | |

− | + | ||

− | + | * A lot of code will be broken by this change. There is no compelling reason to remove these functions outright, rather than gradually deprecating them as with <hask>Prelude.catch</hask>. | |

− | + | * A common pattern is to write a full instance of Monad, then set <hask>fmap = liftM</hask> and <hask>(<*>) = ap</hask>. | |

− | + | ||

− | + | == Split <hask>fail</hask> into its own class == | |

− | + | ||

− | + | ||

− | class | + | |

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

+ | <haskell> | ||

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

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

− | |||

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

− | |||

− | + | == Rename <hask>fmap</hask> to <hask>map</hask> == | |

− | + | ||

− | + | == Export <hask>Applicative</hask> in the Prelude == | |

− | + | == Redefine <hask>>></hask> in terms of <hask>*></hask> rather than <hask>>>=</hask> == | |

+ | |||

+ | == Add a <hask>Pointed</hask> class == | ||

− | |||

− | |||

<haskell> | <haskell> | ||

− | + | class Pointed p where | |

− | + | point :: a -> p a | |

− | + | ||

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

− | |||

− | + | This is already implemented in the [http://hackage.haskell.org/package/pointed pointed] package. | |

− | + | ||

− | + | ||

− | + | === For === | |

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | ||

− | + | === Against === | |

− | + | * This class has seen little real-world use. On Hackage, there are only [http://packdeps.haskellers.com/reverse/pointed 9 reverse dependencies] for <code>pointed</code>, most of which are by the same author. | |

− | + | == Related proposals == | |

− | + | ||

− | + | ||

− | + | ||

− | + | * From early 2011: [http://hackage.haskell.org/trac/ghc/ticket/4834 GHC ticket] – Makes Applicative into a superclass of Monad, but does not deprecate any existing names | |

+ | ** See [http://thread.gmane.org/gmane.comp.lang.haskell.libraries/14883/focus=14905] for the associated discussion. | ||

+ | * [[The Other Prelude]] | ||

− | + | [[Context alias]] would also be a great help with backwards compatibility. The [[class system extension proposal]] may also help. | |

− | + | ||

[[Category:Proposals]] | [[Category:Proposals]] |

## Revision as of 02:05, 3 June 2013

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

This article attempts to document various suggestions that have been brought up over the years, along with arguments for and against.

## 1 Make Applicative a superclass of Monad

Applicative

Monad

class Applicative m => Monad m where ...

### 1.1 For

- Code that is polymorphic over the Monad can use Applicative operators rather than the ugly andliftM.ap

- Most types that implement Monad also implement Applicative already. This change will only make explicit a current best practice.

### 1.2 Against

- Monad is part of standard Haskell, but Applicative is not. If Monad is made a subclass of Applicative, then we will need to add Applicative to the language standard.

- Some libraries, such as blaze-markup, only implement Monad for its do-notation. For these types, an Applicative instance would have no meaning.

## 2 Add join as a method of Monad

join

Monad

class Applicative m => Monad m where (>>=) :: (a -> m b) -> m a -> m b join :: m (m a) -> m a ... m >>= k = join (fmap k m) join m = m >>= id

### 2.1 For

- /fmapis more orthogonal thanjoin/fmap, and the former is closer to the categorical definition.>>=

- is often easier to implement. See [1].join

- The analogous comonad package is written this way.

### 2.2 Against

- is used much more frequently in real-world code than>>=.join

- Performance: The default implementation of requires two traversals. Any container-like type which only implements>>=andfmapwould be slower.join

## 3 Remove liftM, ap, etc. in favor of their Applicative counterparts

liftM

ap

### 3.1 For

- We will end up with a simpler base library.

### 3.2 Against

- A lot of code will be broken by this change. There is no compelling reason to remove these functions outright, rather than gradually deprecating them as with .Prelude.catch

- A common pattern is to write a full instance of Monad, then set andfmap = liftM.(<*>) = ap

## 4 Split fail into its own class

fail

class Monad m => MonadFail m where fail :: String -> m a

## 5 Rename fmap to map

fmap

map

## 6 Export Applicative in the Prelude

Applicative

## 7 Redefine >> in terms of *> rather than >>=

>>

*>

>>=

## 8 Add a Pointed class

Pointed

class Pointed p where point :: a -> p a

This is already implemented in the pointed package.

### 8.1 For

### 8.2 Against

- This class has seen little real-world use. On Hackage, there are only 9 reverse dependencies for
`pointed`

, most of which are by the same author.

## 9 Related proposals

- From early 2011: GHC ticket – Makes Applicative into a superclass of Monad, but does not deprecate any existing names
- See [2] for the associated discussion.

- The Other Prelude

Context alias would also be a great help with backwards compatibility. The class system extension proposal may also help.