【发布时间】:2013-03-20 04:20:29
【问题描述】:
通过我的previous question,我一直在尝试编写一些单子代码。首先,这是我正在使用的状态机函数:
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)
现在,编译正常:
exclaim :: (Monad m) => FSM m
exclaim = FSM exclaim'
exclaim' xs = return (xs ++ "!", exclaim)
但这不是,因为类型声明:
question :: (MonadError String m) => FSM m
question = FSM question'
question' xs
| last xs == '?' = throwError "Already a question"
| otherwise = return (xs ++ "?", question)
错误是Non type-variable argument,我认为是指MonadError之后的String。如果我删除类型声明,我会得到Could not deduce。我知道启用 FlexibleContexts 只是“修复”了这个问题,但是我可以做一些更简单的事情来让我抛出错误吗?我宁愿不启用各种编译器扩展。
完整代码here。
【问题讨论】:
-
FlexibleContexts是一个非常无害的扩展。没有必要害怕这一点。如果没有类型签名,如果禁用单态限制,它也会编译。 -
如果不需要扩展,对扩展有点不利。我宁愿寻找一种替代方法,例如重组代码。解决方案 1 是 FlexibleContexts。还有其他建议吗?
-
或多或少,您将获得的所有解决方案都将是“打开
FlexibleContexts”。不要害怕扩展,它们会为您提供帮助。而这个并不神秘。它是专门让你做你想做的事。不多也不少。