RE: The FunctorM library

On 21 March 2005 01:46, Iavor Diatchki wrote:
On Mon, 21 Mar 2005 00:29:38 +0100, Thomas Jäger
It is already annyoing enough that `Funtor' isn't a subclass of `Monad' although every monad must also be functor.
I think you are right. Does anyone remember why "Functor" is not a superclass of "Monad"?
I think it is because it doesn't need to be. The current situation is slightly more flexible: you don't *have* to provide a Functor instance for every Monad instance. On the other hand, it means you occasionally have to write an additional Functor context in types. You can always get around that by defining class (Functor m, Monad m) => Monad' m where {} Cheers, Simon

Simon Marlow wrote:
On 21 March 2005 01:46, Iavor Diatchki wrote:
On Mon, 21 Mar 2005 00:29:38 +0100, Thomas Jäger
It is already annyoing enough that `Funtor' isn't a subclass of `Monad' although every monad must also be functor.
Yes it is!
I think you are right. Does anyone remember why "Functor" is not a superclass of "Monad"?
I think it is because it doesn't need to be.
Superclasses are never really needed, are they? But they are useful because they make types smaller and more readable. For a given type T which has a Monad instance, you can always declare instance Functor T where fmap = liftM so it is not a big burden to have to declare a Functor instance to accompany a Monad instance. And the Haskell libraries already contain superclass relationships that make less sense than the Functor=>Monad relationship. For example, why is Show and Eq superclasses of Num? Presumably only because it makes types more readable. There are types for which you can declare sensible instances in the Num class, but not so sensible Show or Eq instances: instance Num b => Num (a->b) where (f+g) x = f x + g x negate f x = negate (f x) ... instance Num a => Num (IO a) where ... So, in other words, I think the fact that Functor is not a superclass of Monad is a poorly motivated library design inconsistency...
The current situation is slightly more flexible: you don't *have* to provide a Functor instance for every Monad instance. On the other hand, it means you occasionally have to write an additional Functor context in types. You can always get around that by defining
class (Functor m, Monad m) => Monad' m where {}
Introducing Monad' does not strike me as particularly appealing solution, because 1. For automatically inferred types, it seems pointless, because the compiler would presumably still infer types containing "(Functor m, Monad m) => ..." rather than "Monad' m => ...". 2. To be able to use Monad' in explicitly given type signatures, you would be forced to declare three instances (Functor, Monad, Monad') per type, while if Functor was a superclass of Monad you would only need to declare two instances (Functor, Monad). -- Thomas H

On Mon, 21 Mar 2005 02:23:40 -0800, Thomas Hallgrenwrote: > Simon Marlow wrote: > > And the Haskell libraries already contain superclass relationships that > make less sense than the Functor=>Monad relationship. For example, why > is Show and Eq superclasses of Num? Presumably only because it makes > types more readable. There are types for which you can declare sensible I think the motivation is pattern matching against numeric patterns (Eq) and more readable error messages in case of pattern match failures (Show). Personally, I'd be happy if numeric pattern matching just forced addiditional Eq and Show constraints (pattern matching doesn't make sense in your example anyway). > So, in other words, I think the fact that Functor is not a superclass of > Monad is a poorly motivated library design inconsistency... > > > The current situation is slightly more flexible: you don't *have* to provide a Functor instance for every Monad instance. On the other hand, it means you occasionally have to write an additional Functor context in types. You can always get around that by defining > > > > class (Functor m, Monad m) => Monad' m where {} > > > > > Introducing Monad' does not strike me as particularly appealing > solution, because > > 1. For automatically inferred types, it seems pointless, because the > compiler would presumably still infer types containing "(Functor > m, Monad m) => ..." rather than "Monad' m => ...". > 2. To be able to use Monad' in explicitly given type signatures, you > would be forced to declare three instances (Functor, Monad, > Monad') per type, while if Functor was a superclass of Monad you > would only need to declare two instances (Functor, Monad). 3. There are situations where you are just not able to add a Functor constraint. For example, when defining `lift' for a monad transformer or incidently, when defining a FunctorM instance and you need `m' to be a Functor, all you can do is wrap your monad into a newtype. 4. The more complicated monads get, the more complex a definition of in terms of bind and return becomes, because when defining bind, you're obviously doing two things at once that can be seperated. So more often than not, I find myself defining > instane Monad Foo where > m >>= f = join' $ f `fmap` m where > join' = ... If Functor were a superclass (hopefully, I'm getting it right this time ;)) of monad, join could just be put into the class `Monad' together with a default definition of bind in terms of join and vice versa. 5. Although larger dictionaries have to be carried around, having a Functor instance allows for (presumably) slightly more efficient implementations of library functions, e.g. > liftM2' f x y = x >>= \x' -> f x' `fmap` y Thomas
participants (3)
-
Simon Marlow
-
Thomas Hallgren
-
Thomas Jäger