Haskell"无法演绎","非类型变量参数"

时间:2013-03-19 16:53:57

标签: haskell types

从我的previous question开始,我一直试图找出一些monadic代码。首先,这是我正在使用的状态机功能:

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,我认为这是指String之后的MonadError。如果我删除了类型声明,我会改为Could not deduce。我理解启用FlexibleContexts只是“修复”了这个但是有什么更简单的我可以做以允许我抛出错误?我宁愿不启用各种编译器扩展。

完整代码here

2 个答案:

答案 0 :(得分:4)

如果您绝对不想使用FlexibleContextsNoMonomorphismRestriction,则可以使questionquestion'更加通用,以便在不启用的情况下进行编译模块中的扩展程序:

question :: (Error e, MonadError e m) => FSM m
question = FSM question'

question' :: (Error e, MonadError e m) => String -> m (String, FSM m)
question' xs
    | last xs == '?' = throwError $ strMsg "Already a question"
    | otherwise      = return (xs ++ "?", question)

使用Error使其抛出常规strMsg类型,并指定类型签名。

但我仍然希望启用FlexibleContexts

答案 1 :(得分:4)

详细说明丹尼尔的答案,他的解决方案实际上是避免FlexibleContexts的一般解决方案。

任何时候你都有一个约束:

(SomeTypeConstructor SomeType) => ...

...其中SomeType是触发FlexibleInstances警告的某种具体类型,您可以通过类型对要在{{1}上使用的操作进行分类来解决FlexibleContexts },例如:

SomeType

...然后将class IsSomeType t where get :: t -> SomeType set :: SomeType -> t -> t 合并到约束中:

IsSomeType

...并仅使用(IsSomeType t, SomeTypeConstructor t) => ... 中的方法。