From my previous question, I've been trying to work out some monadic code. To start, here is a state machine function I'm using:
import Control.Monad
import Control.Monad.Error
newtype FSM m = FSM { unFSM :: String -> m (String, FSM m) }
fsm f [] = return []
fsm f (r:rs) = do
(xs, f') <- unFSM f r
liftM (xs:) (fsm f' rs)
Now, this compiles fine:
exclaim :: (Monad m) => FSM m
exclaim = FSM exclaim'
exclaim' xs = return (xs ++ "!", exclaim)
But this doesn't, because of the type declaration:
question :: (MonadError String m) => FSM m
question = FSM question'
question' xs
| last xs == '?' = throwError "Already a question"
| otherwise = return (xs ++ "?", question)
The error is Non type-variable argument, which I think is referring to the String after MonadError. If I remove the type declaration, I get Could not deduce instead. I understand enabling FlexibleContexts just "fixes" this but is there something simpler I could be doing to allow me to throw errors? I'd rather not be enabling all sorts of compiler extensions.
Full code here.
FlexibleContextsis a quite harmless extension. No need to be afraid of that. Without the type signature, it also compiles if you disable the monomorphism restriction. - Daniel FischerFlexibleContexts". Don't be afraid of extensions, they're there to help you. And this one isn't mysterious. It is specifically to allow you to do exactly what you want to do. Nothing more, nothing less. - Carl