考虑以下错误的解析器编写为StateT
。
type Parser a = StateT String Maybe a -- Maybe is chosen arbitrarily here.
oneDigit :: Parser Int
oneDigit = do
(x : _) <- get
return (read x :: Int)
它抛出以下错误:
No instance for (MonadState [String] (StateT String Maybe))
然而,当我改为oneChar :: Parser Char
时,这种情况并没有发生。
我的结论是,如果您的州为Parser a
,则只能定义m a
现在我的问题是,我如何放宽这种耦合要求?
答案 0 :(得分:6)
您的州是String
,如果您(x : _) <- get
,则x
是Char
。您无法在read
上使用Char
。打印错误是由于类型推断反过来起作用:从read x
编译器推断x
是String
,这意味着您的状态为[String]
,Parser a
不适用。具体来说,错误表明(StateT String Maybe)
不是MonadState [String]
的实例,这是真的,因为它是MonadState String
的实例。你可以从GHCI看到它:
> import Control.Monad.State
> :i StateT
...
instance Monad m => MonadState s (StateT s m)
您案件中的s == String
。
现在,如果您想将字符串中的下一个Char
读取为数字(0到9之间的数字),则需要将read
替换为digitToInt
来自{{ 1}}:
Data.Char
答案 1 :(得分:3)
类型错误试图告诉您,您的状态需要是字符串列表而不是单个字符串,因为您使用
(x : _) <- get
获取列表的第一个元素,然后使用read
(期望String
)读取它。
由于您只想解析单个数字,因此可以将功能更改为
oneDigit :: Parser Int
oneDigit = do
(x : _) <- get
return (read [x] :: Int)
[x]
从单个字符创建一个字符串(因为String
只是[Char]
的别名)。
请注意,您可能不希望在解析器实现中使用read
,因为它会因无效输入而崩溃。 reads
是一个更好的替代方案,可以让您处理错误案例。例如:
oneDigit :: Parser Int
oneDigit = do
(x : xs) <- get
case reads [x] of
[(n, "")] -> put xs >> return n
_ -> lift Nothing
这也将put
字符串的其余部分返回到状态,以便解析器在成功时实际消耗输入。