MonadPlus or Alternative or ...?

I want to generalize a set of functions from lists to some functor type. I require the following three operation types. f a a -> f a f a -> f a -> f a Should I choose MonadPlus and use these? mzero return mplus Or should I choose Alternative and use these? empty pure (<|>) Or should I make my own class? Or is there another option? Thanks, Sean

Check the laws that instances of MonadPlus and Alternative should comply with to help you make your decision. Cheers Mark Sean Leather wrote:
I want to generalize a set of functions from lists to some functor type. I require the following three operation types.
f a a -> f a f a -> f a -> f a
Should I choose MonadPlus and use these?
mzero return mplus
Or should I choose Alternative and use these?
empty pure (<|>)
Or should I make my own class? Or is there another option?
Thanks, Sean ------------------------------------------------------------------------
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On May 2, 2010, at 1:11 AM, Sean Leather wrote:
I want to generalize a set of functions from lists to some functor type. [...] Should I choose MonadPlus and use these? [...] Or should I choose Alternative and use these? [...]
There are some types that can be an instance of Alternative but not of MonadPlus (because they are not a monad but an applicative functor). Hence, if you choose Alternative, then your functions are more generally applicable. In practice, there may be instances of MonadPlus for wich their authors chose not to provide an Alternative instance and your functions then could not be applied to those types. But every MonadPlus instance `m` can be made an Alternative instance by declaring instance Functor m where fmap = liftM instance Applicative m where pure = return (<*>) = ap instance Alternative m where empty = mzero (<|>) = mplus The laws required by MonadPlus imply the laws required by theses instances.
Or should I make my own class?
Then, there obviously won't be any instances for existing types other than your own (which might be a good or bad thing). You may want to do this, if you don't want to require either (>>=) or (<*>), which may not be supported for reasonable instances of your own class.
Or is there another option?
If you have functions that do not need return/pure you can also use a Monoid constraint on those functions and replace empty/mzero with mempty and <|>/mplus with mappend. Again, those functions share the same laws. Ideally, every MonadPlus instance would also be an Alternative instance and every Alternative instance would be an instance of Monoid. You may find it unfortunate that there are so many operations for the same thing but until the (Applicative/Monad) class hierarchy is refactored, we have to live with it. Sebastian -- Underestimating the novelty of the future is a time-honored tradition. (D.G.)

On Sun, May 2, 2010 at 10:23, Sebastian Fischer wrote:
On May 2, 2010, at 1:11 AM, Sean Leather wrote:
I want to generalize a set of functions from lists to some functor type.
[...] Should I choose MonadPlus and use these? [...] Or should I choose Alternative and use these? [...]
There are some types that can be an instance of Alternative but not of MonadPlus (because they are not a monad but an applicative functor). Hence, if you choose Alternative, then your functions are more generally applicable.
Right. Point for Alternative. In practice, there may be instances of MonadPlus for wich their authors
chose not to provide an Alternative instance and your functions then could not be applied to those types. But every MonadPlus instance `m` can be made an Alternative instance by declaring [...]
Or by using WrappedMonad I suppose. That makes me wonder. Should there be Applicative and Alternative instances of ReadP, ReadPrec, and P (whatever that is)? There are MonoidPlus instances [1]. [1] http://haskell.org/ghc/docs/6.12.1/html/libraries/base-4.2.0.0/Control-Monad... Or should I make my own class?
Then, there obviously won't be any instances for existing types other than your own (which might be a good or bad thing). You may want to do this, if you don't want to require either (>>=) or (<*>), which may not be supported for reasonable instances of your own class.
I don't really want to do this option, because it increases the understanding overhead needlessly, I think. Everything else that is provided by Applicative/Monad doesn't matter. I require only the three operations above and do not disallow extra operations.
Or is there another option?
If you have functions that do not need return/pure you can also use a Monoid constraint on those functions and replace empty/mzero with mempty and <|>/mplus with mappend. Again, those functions share the same laws.
Yeah, I first started with Monoid, but I've come to the conclusion that I need a container with return/pure. Ideally, every MonadPlus instance would also be an Alternative instance and
every Alternative instance would be an instance of Monoid. You may find it unfortunate that there are so many operations for the same thing but until the (Applicative/Monad) class hierarchy is refactored, we have to live with it.
I run into this kind of situation often. I would really like to see a better division of operations between classes. Thanks for the response, Sebastian! Sean

On May 2, 2010, at 11:10 AM, Sean Leather wrote:
Or should I make my own class?
Then, there obviously won't be any instances for existing types other than your own (which might be a good or bad thing). You may want to do this, if you don't want to require either (>>=) or (<*>), which may not be supported for reasonable instances of your own class.
I don't really want to do this option, because it increases the understanding overhead needlessly, I think. Everything else that is provided by Applicative/Monad doesn't matter. I require only the three operations above and do not disallow extra operations.
By not making your own class, you prohibit types that do not support <*> (or >>=). That's fine, but an additional burden to instance writers. By not listing extra operations in your own class you would not disallow them. You require them by not making your own class without them. But still, your wish to reuse existing classes may be a fine reason to impose an additional burden. Sebastian -- Underestimating the novelty of the future is a time-honored tradition. (D.G.)

On Sun, May 2, 2010 at 12:07, Sebastian Fischer wrote:
On May 2, 2010, at 11:10 AM, Sean Leather wrote:
Or should I make my own class?
Then, there obviously won't be any instances for existing types other than your own (which might be a good or bad thing). You may want to do this, if you don't want to require either (>>=) or (<*>), which may not be supported for reasonable instances of your own class.
I don't really want to do this option, because it increases the understanding overhead needlessly, I think. Everything else that is provided by Applicative/Monad doesn't matter. I require only the three operations above and do not disallow extra operations.
By not making your own class, you prohibit types that do not support <*> (or >>=). That's fine, but an additional burden to instance writers. By not listing extra operations in your own class you would not disallow them. You require them by not making your own class without them.
Understood and agreed. Having my own class would be the most flexible in what it allows and disallows. But still, your wish to reuse existing classes may be a fine reason to
impose an additional burden.
There is an additional maintenance burden that I've recently become aware of, considering I haven't done a very good job of maintaining my own code. ;) To use my own class, I should reasonably provide instances for everything that I possibly can. This would include (at least) lists, Maybe, WrappedAlternative, and WrappedMonadPlus. Who knows? I may change my mind in a while. In that case, would you have any suggestions on a name for such a class or names for the methods? ;) class C f where zero :: f a one :: a -> f a append :: f a -> f a -> f a Sean

would you have any suggestions on a name for such a class or names for the methods?
I'm afraid I don't. I'd like class Pointed t where point :: a -> t a class Monoid m where id :: m (.) :: m -> m -> m constraint Monoidy t = (Pointed t, Monoid (t a)) (although I'm not a big fan of the involved names except for the Monoid class) But the above is currently impractical for various reasons ;) (more than those listed in [1]). Sebastian [1] Haskell Type Constraints Unleashed http://www.cs.kuleuven.be/~toms/Research/papers/constraint_families.pdf -- Underestimating the novelty of the future is a time-honored tradition. (D.G.)

On Sun, May 2, 2010 at 4:23 AM, Sebastian Fischer < sebf@informatik.uni-kiel.de> wrote:
Ideally, every MonadPlus instance would also be an Alternative instance and every Alternative instance would be an instance of Monoid. You may find it unfortunate that there are so many operations for the same thing but until the (Applicative/Monad) class hierarchy is refactored, we have to live with it.
Sadly there is at least one MonadPlus/Alternative and Monoid instance that differs: Maybe The Monoid instance for Maybe is the lifting of a semigroup into a monoid by adding an identity element, but unfortunately, it does so rather poorly as there is no semigroup class that it can assume for its argument, and so it lifts a monoid into a monoid, while avoiding the use of the underlying definition for mempty. =/ So there is no path forward that doesn't change the meaning of existing programs that makes the Alternative and Monoid instances agree on all Applicatives. -Edward Kmett

On Sat, May 1, 2010 at 7:11 PM, Sean Leather
I want to generalize a set of functions from lists to some functor type. I require the following three operation types.
f a a -> f a f a -> f a -> f a
Since f is a functor, FunctorPlus and Pointed together get you exactly the subset of functionality that you want. Whether or not category-extras can be considered a light weight dependency on the other hand is another thing entirely. ;) -Edward Kmett
participants (4)
-
Edward Kmett
-
Mark Wassell
-
Sean Leather
-
Sebastian Fischer