Description
On the heels of #141, we now have that the Apply
and Bind
instances for a data type have to agree when that data type also has a Monad
. It seems like we're still missing something.
With the laws as they're written, you can have a Bind
instance for a data type that doesn't agree with its Apply
instance, so long as said data type does not also define a Monad
instance. I think that's not right. I think we want to make sure that the Apply
and Bind
instances agree.
A real data type that could sneak a lawful Bind
instance in as the laws are now is Data.Validation.Semigroup.V
:
instance bindV :: (Semigroup a) => Bind (V a) where
bind = flip (unV invalid)
I'm pretty sure that definition is associative, but it will "short-circuit" at the first invalid case. That doesn't agree with the Apply
instance (which accumulates invalid cases).
I'm proposing that we change ap
to something like:
ap :: forall a b f. Bind f => f (a -> b) -> f a -> f b
ap f a = bind f (mapFlipped a)
And move the Applicative Superclass
law to Bind
(probably change the name of the law as well).
Thoughts?