Ross Paterson | 24 Jun 19:17 2013
Picon

MonadPlus instance for ContT

Alistair Lynn has proposed the following instance:

  instance (Monoid r, Monad m) => MonadPlus (ContT r m) where
    mzero = ContT $ const $ return mempty
    m `mplus` n = ContT $ \ c -> liftM2 mappend (runContT m c) (runContT n c)

but this would also be possible:

  instance (MonadPlus m) => MonadPlus (ContT r m) where
    mzero = ContT $ const mzero
    m `mplus` n = ContT $ \ c -> runContT m c `mplus` runContT n c

Is one of them better?
John Wiegley | 24 Jun 19:43 2013

Re: MonadPlus instance for ContT

>>>>> Ross Paterson <R.Paterson <at> city.ac.uk> writes:

> Alistair Lynn has proposed the following instance:
>
>   instance (Monoid r, Monad m) => MonadPlus (ContT r m) where
>     mzero = ContT $ const $ return mempty
>     m `mplus` n = ContT $ \ c -> liftM2 mappend (runContT m c) (runContT n c)
>
> but this would also be possible:
>
>   instance (MonadPlus m) => MonadPlus (ContT r m) where
>     mzero = ContT $ const mzero
>     m `mplus` n = ContT $ \ c -> runContT m c `mplus` runContT n c
>
> Is one of them better?

I would think that allowing ContT to transform any Monad over any Monoid has
more utility than only transforming another MonadPlus.  But I have no real
world data to back this up, just a hunch.

--

-- 
John Wiegley
FP Complete                         Haskell tools, training and consulting
http://fpcomplete.com               johnw on #haskell/irc.freenode.net
Henning Thielemann | 24 Jun 19:53 2013
Picon

Re: MonadPlus instance for ContT


On Mon, 24 Jun 2013, John Wiegley wrote:

>>>>>> Ross Paterson <R.Paterson <at> city.ac.uk> writes:
>
>> Alistair Lynn has proposed the following instance:
>>
>>   instance (Monoid r, Monad m) => MonadPlus (ContT r m) where
>>     mzero = ContT $ const $ return mempty
>>     m `mplus` n = ContT $ \ c -> liftM2 mappend (runContT m c) (runContT n c)
>>
>> but this would also be possible:
>>
>>   instance (MonadPlus m) => MonadPlus (ContT r m) where
>>     mzero = ContT $ const mzero
>>     m `mplus` n = ContT $ \ c -> runContT m c `mplus` runContT n c
>>
>> Is one of them better?
>
> I would think that allowing ContT to transform any Monad over any Monoid has
> more utility than only transforming another MonadPlus.  But I have no real
> world data to back this up, just a hunch.

I guess that if someone has a MonadPlus monad, then he wants to continue 
to use it when the monad stack grows by a ContT. This would give 
preference to the second instance.
Edward Kmett | 24 Jun 20:23 2013
Picon

Re: MonadPlus instance for ContT

I agree with Henning.


I've historically used the moral equivalent of the second one far more than the first.

I have used both though. For instance, Numeric.Covector in the algebra package is a semantically restricted form of Cont that uses the equivalent of the first method.

The second form goes out of its way to preserve more of the existing semantics of the transformer stack and I'd dare say that if such an instance was added, it'd be closer to the expected behavior for more users.

-Edward

On Mon, Jun 24, 2013 at 1:53 PM, Henning Thielemann <lemming <at> henning-thielemann.de> wrote:

On Mon, 24 Jun 2013, John Wiegley wrote:

Ross Paterson <R.Paterson <at> city.ac.uk> writes:

Alistair Lynn has proposed the following instance:

  instance (Monoid r, Monad m) => MonadPlus (ContT r m) where
    mzero = ContT $ const $ return mempty
    m `mplus` n = ContT $ \ c -> liftM2 mappend (runContT m c) (runContT n c)

but this would also be possible:

  instance (MonadPlus m) => MonadPlus (ContT r m) where
    mzero = ContT $ const mzero
    m `mplus` n = ContT $ \ c -> runContT m c `mplus` runContT n c

Is one of them better?

I would think that allowing ContT to transform any Monad over any Monoid has
more utility than only transforming another MonadPlus.  But I have no real
world data to back this up, just a hunch.

I guess that if someone has a MonadPlus monad, then he wants to continue to use it when the monad stack grows by a ContT. This would give preference to the second instance.


_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries
Dan Burton | 24 Jun 20:53 2013
Picon

Re: MonadPlus instance for ContT

I also agree with Henning.


If anything, the 1st instance could be a ContT instance for Monoid.

instance (Monoid r, Monad m) => Monoid (ContT r m a) where
  mempty = ContT $ const $ return mempty
  m `mappend` n = ContT $ \ c -> liftM2 mappend (runContT m c) (runContT n c)

That way both behaviors are easily accessible. Is there any other sensible ContT instance for Monoid?

-- Dan Burton


On Mon, Jun 24, 2013 at 11:23 AM, Edward Kmett <ekmett <at> gmail.com> wrote:
I agree with Henning.

I've historically used the moral equivalent of the second one far more than the first.

I have used both though. For instance, Numeric.Covector in the algebra package is a semantically restricted form of Cont that uses the equivalent of the first method.

The second form goes out of its way to preserve more of the existing semantics of the transformer stack and I'd dare say that if such an instance was added, it'd be closer to the expected behavior for more users.

-Edward

On Mon, Jun 24, 2013 at 1:53 PM, Henning Thielemann <lemming <at> henning-thielemann.de> wrote:

On Mon, 24 Jun 2013, John Wiegley wrote:

Ross Paterson <R.Paterson <at> city.ac.uk> writes:

Alistair Lynn has proposed the following instance:

  instance (Monoid r, Monad m) => MonadPlus (ContT r m) where
    mzero = ContT $ const $ return mempty
    m `mplus` n = ContT $ \ c -> liftM2 mappend (runContT m c) (runContT n c)

but this would also be possible:

  instance (MonadPlus m) => MonadPlus (ContT r m) where
    mzero = ContT $ const mzero
    m `mplus` n = ContT $ \ c -> runContT m c `mplus` runContT n c

Is one of them better?

I would think that allowing ContT to transform any Monad over any Monoid has
more utility than only transforming another MonadPlus.  But I have no real
world data to back this up, just a hunch.

I guess that if someone has a MonadPlus monad, then he wants to continue to use it when the monad stack grows by a ContT. This would give preference to the second instance.


_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries


_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries


_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries
Edward Kmett | 24 Jun 21:07 2013
Picon

Re: MonadPlus instance for ContT

On Mon, Jun 24, 2013 at 2:53 PM, Dan Burton <danburton.email <at> gmail.com> wrote:

I also agree with Henning.

If anything, the 1st instance could be a ContT instance for Monoid.

instance (Monoid r, Monad m) => Monoid (ContT r m a) where
  mempty = ContT $ const $ return mempty
  m `mappend` n = ContT $ \ c -> liftM2 mappend (runContT m c) (runContT n c)

That way both behaviors are easily accessible. Is there any other sensible ContT instance for Monoid?
 
Yes.

The third construction is the 'universal' lifting that works for every Applicative, which would look like:

instance (Monad m, Monoid a) => Monoid (ContT r m a) where
  mempty = return mempty
  mappend = liftM2 mappend

-Edward

_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries
John Wiegley | 24 Jun 21:20 2013

Re: MonadPlus instance for ContT

>>>>> Edward Kmett <ekmett <at> gmail.com> writes:

> The third construction is the 'universal' lifting that works for every
> Applicative, which would look like:

> instance (Monad m, Monoid a) => Monoid (ContT r m a) where
>   mempty = return mempty
>   mappend = liftM2 mappend

Why not then this?  That is, once AMP is out...

    instance (Applicative m, Monoid a) => Monoid (m a) where
        mempty  = pure mempty
        mappend = liftA2 mappend

--

-- 
John Wiegley
FP Complete                         Haskell tools, training and consulting
http://fpcomplete.com               johnw on #haskell/irc.freenode.net

_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries
Edward Kmett | 24 Jun 21:26 2013
Picon

Re: MonadPlus instance for ContT

Because there are many monads for which you do not want this construction!


It isn't what you mean when you use mappend on [a] for sure! It is also different from the behavior for Monad, and it rules out those and many many other perfectly valid uses by overlap.

-Edward

On Mon, Jun 24, 2013 at 3:20 PM, John Wiegley <johnw <at> fpcomplete.com> wrote:
>>>>> Edward Kmett <ekmett <at> gmail.com> writes:

> The third construction is the 'universal' lifting that works for every
> Applicative, which would look like:

> instance (Monad m, Monoid a) => Monoid (ContT r m a) where
>   mempty = return mempty
>   mappend = liftM2 mappend

Why not then this?  That is, once AMP is out...

    instance (Applicative m, Monoid a) => Monoid (m a) where
        mempty  = pure mempty
        mappend = liftA2 mappend

--
John Wiegley
FP Complete                         Haskell tools, training and consulting
http://fpcomplete.com               johnw on #haskell/irc.freenode.net

_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
Libraries <at> haskell.org
http://www.haskell.org/mailman/listinfo/libraries
John Wiegley | 24 Jun 21:54 2013

Re: MonadPlus instance for ContT

>>>>> Edward Kmett <ekmett <at> gmail.com> writes:

> Because there are many monads for which you do not want this construction!
>
> It isn't what you mean when you use mappend on [a] for sure! It is also
> different from the behavior for Monad, and it rules out those and many many
> other perfectly valid uses by overlap.

Thanks for the clarification, Edward!  Very good points.

--

-- 
John Wiegley
FP Complete                         Haskell tools, training and consulting
http://fpcomplete.com               johnw on #haskell/irc.freenode.net
Ross Paterson | 24 Jun 22:03 2013
Picon

Re: MonadPlus instance for ContT

On Mon, Jun 24, 2013 at 11:53:06AM -0700, Dan Burton wrote:
> If anything, the 1st instance could be a ContT instance for Monoid.
> 
> instance (Monoid r, Monad m) => Monoid (ContT r m a) where
>   mempty = ContT $ const $ return mempty
>   m `mappend` n = ContT $ \ c -> liftM2 mappend (runContT m c) (runContT n c)
> 
> That way both behaviors are easily accessible.

There's a school of thought that holds that the Monoid and Alternative
(and therefore MonadPlus) instances on any functor should agree:

http://thread.gmane.org/gmane.comp.lang.haskell.cafe/94642

Gmane