Ralf Hinze wrote:

> By chance, I noticed that the resolution of constraints in combination
> with overlapping instances has changed in the `September 1999' version
> of Hugs.
>
> This code scrap used to run ...
>
> > import Monad
>
> > instance (Monad m) => Functor m where
> >     fmap f m          =  m >>= return . f
>
>   class (Monad m) => MonadPlus m where
>       mzero             :: m a
>       mplus             :: m a -> m a -> m a
>
> > wrap                  :: (MonadPlus m) => m a -> m (Maybe a)
> > wrap m                =  fmap Just m `mplus` return Nothing
>
> Now, Hugs (hugs +o) reports
>
> ERROR "Map.lhs" (line 7): Cannot justify constraints in explicitly typed binding
> *** Expression    : wrap
> *** Type          : MonadPlus a => a b -> a (Maybe b)
> *** Given context : MonadPlus a
> *** Constraints   : Functor a
>
> However, an instance of `MonadPlus' is also an instance of `Monad' and
> the first instance declaration formalizes, that a `Monad' instance is
> also an instance of `Functor' (of course, this instance overlaps with
> all other instances).
>
> Is this a deliberate change or a bug?

Deliberate change.  What you say is true: the first instance declaration
formalizes, that a `Monad' instance is also an instance of `Functor', so it's
reasonable to expect that hugs would just use that instance decl to build the
instance of `fmap' used in `wrap'.

But your following comment is even more important: "of course, this instance
overlaps with all other instances."  Now, ordinarily, overlapping instances are
resolved so that a more specific instance is always chosen in preference to a more
general one.  If I typed in `wrap [1, 2, 3]', which instance of `fmap' would you
expect to be used?  By the general overlapping instance rule, we'd expect the List
instance of Functor to be used.  However, what hugs previously did is chose the
`Monad m => Functor m' instance, thus silently overriding the overlapping mechanism
by chosing always the more general instance.

Is this what you meant it to do?  We decided that hugs shouldn't silently make this
decision for you.

Looking at the signature of wrap again, by omitting `Functor' from the context, you
are telling hugs to commit to a particular instance for `Functor'.  Previously, it
chose the more general instance.  Now, it recognizes that it's too early to commit
to a choice, because there are also more specific instances of `Functor' around,
and it's too early to rule them out.

So, the solution is simply to put `Functor m' in the signature for `wrap'.

--Jeff

Reply via email to