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

Akio Takano tkn.akio at gmail.com
Fri Nov 27 09:50:12 UTC 2015


On Thu, Nov 26, 2015 at 5:08 PM, Edward Kmett <ekmett at gmail.com> wrote:
> On Thu, Nov 26, 2015 at 3:28 AM, Akio Takano <tkn.akio at gmail.com> 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


More information about the Libraries mailing list