Monad of no `return` Proposal (MRP): Moving `return` out of `Monad`

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
243 messages Options
1 ... 10111213
Reply | Threaded
Open this post in threaded view
|

Re: MRP Summary & revised MRP 2ed (was: Monad of no `return` Proposal (MRP): Moving `return` out of `Monad`)

Akio Takano
On Thu, Nov 26, 2015 at 5:08 PM, Edward Kmett <[hidden email]> wrote:
> On Thu, Nov 26, 2015 at 3:28 AM, Akio Takano <[hidden email]> wrote:
>>
>> This is true, but I think it's much better to avoid breaking people's
>> code in the first place. Also, since the breakage can be silent, one
>> will not always be able to make a fix promptly.
>
>
> We're not talking about making this change until we can get some warnings in
> place.

I would appreciate such a warning. I was concerned because I didn't
find a plan for one on the proposal page. In particular, neither the
proposed -fwarn-mrp-compat flag nor the implemented
-fwarn-noncanonical-monad-instances flag seemed to protect a
programmer from the issue of silent performance regression, when there
is no explicit definition for (*>) nor for (>>).

>
> That said, in the presence of some existing combinators that have already
> been generalized from Monad to Applicative you may want to ensure that these
> definitions have been fixed already.
>
>> >
>> > In situations where (<*>) is asymptotically more efficient than (>>=)
>> > then
>> > the default definition in terms of (<*>) wins.
>>
>> You are right. I hadn't thought about this.
>>
>> >
>> > Right now, if you run through hackage there are lots of places where
>> > (>>)
>> > has been manually improved but the (*>) has not -- or vice versa. We
>> > have
>> > two places where people should apply an optimization and many have only
>> > realized that they should optimize one or the other.
>> >
>> > The key here is to encourage folks to actually define (*>) when it
>> > matters.
>>
>> I understand this, but perhaps there is a way to achieve this without
>> slowing down existing code. How about introducing a new warning
>> (enabled with -Wall) that is triggered when a type satisfies the
>> following 3 conditions?
>>
>> 1. The type has a Monad instance and an Applicative instance declared
>> in the same module, with the same set of constraints.
>> 2. (*>) is not defined as (*>) = (>>). i.e. either it has a
>> non-trivial definition or its definition is left out.
>> 3. (>>) is not defined as (>>) = (*>). i.e. either it has a
>> non-trivial definition or its definition is left out.
>>
>> This way, people can be warned when (*>) and (>>) can share an
>> implementation but they don't.
>
>
> This is pretty much what Herbert has been working on, except with the
> definition biased in favor of (>>) = (*>) being expected, and the other
> becoming a warning as that definition blows up when and if we later move
> (>>) out of the class.

Probably I wasn't clear, but I actually wanted to suggest a warning as
a replacement for (the (>>)-related half of) MRP, not as a migration
path to it. If the goal is to encourage people to have a good
implementation for (*>), it may be achievable with just a warning,
with no change to the class hierarchy.

That said, I can imagine having a warning like this as a migration
path. In that case we could provide a function like

thenDefaultByBind :: (Monad m) => m a -> m b -> m b
thenDefaultByBind a b = a >>= \_ -> b

and give people an option to define

(*>) = thenDefaultByBind

in their Applicative instances.

- Akio

>
> -Edward
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: MRP Summary & revised MRP 2ed

Akio Takano
In reply to this post by Herbert Valerio Riedel-3
On Fri, Nov 27, 2015 at 9:42 AM, Herbert Valerio Riedel
<[hidden email]> wrote:
> You're right, from what I've seen the majority of Monad instances don't
> bother to override (>>)/(*>) currently.
>
> But do we really want every Applicative/Monad to explicitly define (*>)
> (and consequently (>>)=(*>)) ?

You are right, this indeed seems like a strange thing to require.
However I believe that this is much better than silently changing the
default definition for (>>) to something that potentially has worse
asymptotic behaviors.

Of course another option is to keep (>>) in the Monad class.

- Akio

>
> If so, it seems to be unfortunate that we have an overridable default
> implementation for (*>)/(>>) in place, as that IMO suggests that you're
> only supposed to override (*>) in those less common cases where it
> provides a benefit over the default implementation. What's the point of
> the default implementation otherwise?
>
>
> -- hvr
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: MRP Summary & revised MRP 2ed (was: Monad of no `return` Proposal (MRP): Moving `return` out of `Monad`)

Edward Kmett-2
In reply to this post by Akio Takano
I understand that you'd prefer it as a replacement for this plan than as a supplement, but I don't think that that would work all that well. We already have half a dozen combinators in Control.Monad generalized, more are generalizing in 7.10. e.g. We don't want to introduce a 'replicateA_' for instance as the pattern has been to generalize the existing 'M' combinators where possible.

What you propose would leave us paralyzed in an difficult to explain middle ground indefinitely.

As for making a thenM or thenDefault or thenDefaultByBind to make it easier to define (*>), I'm 100% on board with that.

-Edward

On Fri, Nov 27, 2015 at 4:50 AM, Akio Takano <[hidden email]> wrote:
On Thu, Nov 26, 2015 at 5:08 PM, Edward Kmett <[hidden email]> wrote:
> On Thu, Nov 26, 2015 at 3:28 AM, Akio Takano <[hidden email]> wrote:
>>
>> This is true, but I think it's much better to avoid breaking people's
>> code in the first place. Also, since the breakage can be silent, one
>> will not always be able to make a fix promptly.
>
>
> We're not talking about making this change until we can get some warnings in
> place.

I would appreciate such a warning. I was concerned because I didn't
find a plan for one on the proposal page. In particular, neither the
proposed -fwarn-mrp-compat flag nor the implemented
-fwarn-noncanonical-monad-instances flag seemed to protect a
programmer from the issue of silent performance regression, when there
is no explicit definition for (*>) nor for (>>).

>
> That said, in the presence of some existing combinators that have already
> been generalized from Monad to Applicative you may want to ensure that these
> definitions have been fixed already.
>
>> >
>> > In situations where (<*>) is asymptotically more efficient than (>>=)
>> > then
>> > the default definition in terms of (<*>) wins.
>>
>> You are right. I hadn't thought about this.
>>
>> >
>> > Right now, if you run through hackage there are lots of places where
>> > (>>)
>> > has been manually improved but the (*>) has not -- or vice versa. We
>> > have
>> > two places where people should apply an optimization and many have only
>> > realized that they should optimize one or the other.
>> >
>> > The key here is to encourage folks to actually define (*>) when it
>> > matters.
>>
>> I understand this, but perhaps there is a way to achieve this without
>> slowing down existing code. How about introducing a new warning
>> (enabled with -Wall) that is triggered when a type satisfies the
>> following 3 conditions?
>>
>> 1. The type has a Monad instance and an Applicative instance declared
>> in the same module, with the same set of constraints.
>> 2. (*>) is not defined as (*>) = (>>). i.e. either it has a
>> non-trivial definition or its definition is left out.
>> 3. (>>) is not defined as (>>) = (*>). i.e. either it has a
>> non-trivial definition or its definition is left out.
>>
>> This way, people can be warned when (*>) and (>>) can share an
>> implementation but they don't.
>
>
> This is pretty much what Herbert has been working on, except with the
> definition biased in favor of (>>) = (*>) being expected, and the other
> becoming a warning as that definition blows up when and if we later move
> (>>) out of the class.

Probably I wasn't clear, but I actually wanted to suggest a warning as
a replacement for (the (>>)-related half of) MRP, not as a migration
path to it. If the goal is to encourage people to have a good
implementation for (*>), it may be achievable with just a warning,
with no change to the class hierarchy.

That said, I can imagine having a warning like this as a migration
path. In that case we could provide a function like

thenDefaultByBind :: (Monad m) => m a -> m b -> m b
thenDefaultByBind a b = a >>= \_ -> b

and give people an option to define

(*>) = thenDefaultByBind

in their Applicative instances.

- Akio

>
> -Edward


_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
1 ... 10111213