[Haskell-cafe] flexible contexts problem
Luke Palmer
lrpalmer at gmail.com
Sat Sep 12 20:29:55 EDT 2009
2009/9/12 Sean McLaughlin <seanmcl at gmail.com>:
> I'm having trouble understanding the following behavior. The following
> program compiles:
> {-# OPTIONS_GHC -XMultiParamTypeClasses -XFlexibleContexts #-}
> import Control.Monad.State
> class Has α s where
> has :: s -> (α, s)
> project :: (MonadState s m, Has α s) => m α
> project = do (α, s) <- gets has
> put s
> return α
> f :: (MonadState s m, Has Int s) => m Int
> f = do x <- project
> return x
> However, if you replace the function f with
> f :: (MonadState s m, Has Int s) => m Int
> f = do x <- project
> y <- project
> return x
> then it fails with the error
> Could not deduce (Has α s)
> from the context (MonadState s m, Has Int s)
> arising from a use of `project'
> at /Users/sean/uploads/Weird.hs:16:12-18
> Possible fix:
> add (Has α s) to the context of the type signature for `f'
> In a stmt of a 'do' expression: y <- project
> In the expression:
> do x <- project
> y <- project
> return x
> In the definition of `f':
> f = do x <- project
> y <- project
> return x
>
> I don't see how the second call to project could possibly make a difference.
> Could
> someone please tell me what I'm doing wrong?
Look at the type signature of project:
project :: (MonadState s m, Has α s) => m α
The only way it can know what Has instance to use is by knowing α.
And the only way to know α is to know the return type. You never use
y in your new f, which is the only thing that could have told the
compiler what type α was for the second project call (it's not
necessarily the same as in the first).
Possible solutions:
* Use fundeps to constrain Has so there is only one choice of α for
each choice of s. Do this only if this constraint correctly models
the meaning of Has (which is... what?)
* Give the compiler some way of knowing what type y is, eg.
f :: (MonadState s m, Has Int s) => m Int
f = do x <- project
y :: Int <- project
return x
Returning it or taking something of its type as a parameter
(constraining with asTypeOf) is just as good, then a constraint can be
added to the context.
Luke
More information about the Haskell-Cafe
mailing list