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