Frank Atanassow wrote:

> Here is a program which uses GHC's FiniteMap and Andy Gill's monad library:
>
>   varId :: String -> State (Int, FiniteMap String Int) Int
>   varId s = do (n, e) <- get
>             return n
>
> BTW, the monad library defines:
>
>   class (Monad m) => MonadState s m where
>          get :: m s
>          put :: s -> m ()
>
>   instance MonadState s (State s) where ...
>
> But hugs -98 (February 2000) complains with:
>
>   ERROR "Infer.lhs" (line 162): Cannot justify constraints in explicitly typed 
>binding
>   *** Expression    : varId
>   *** Type          : String -> State (Int,FiniteMap String Int) Int
>   *** Given context : ()
>   *** Constraints   : MonadState (Int,a) (State (Int,FiniteMap String Int))
>
> which would be correct if I had not restricted the type, but clearly the
> constraints can be satisfied

Define `clearly' ;-)  Unfortunately, in Haskell 98 (w/ multi-param type classes) this 
is
not the case - many instances could satisfy that constraint.  You could also define, 
for
example, an `instance MonadState (Int,Bool) (State (Int,FiniteMap String Int))'.
Nevermind that we never intend to have such instances - Haskell doesn't know that.

The problem is that there's an interesting assumption that we make that Haskell doesn't
know about: for all instances of MonadState, `s' is uniquely determined by `m'.  Notice
that he instance decl from the MonadState module is consistent with this assumption.  
We
can express this assumption using an extension called `functional depdendencies', which
allows us to tell Haskell which parameters in a multi parameter type class depend on
other parameters.  Using functional dependencies, we'd express the MonadState class as:

    Class Monad m => MonadState s m | m -> s where ...

With this class decl, your program would be accepted.  See the hugs manual for more
details.

--Jeff

Reply via email to