我想直接使用getParserState
完成访问parsecs输入流。为了从流中读取,提供了uncons
方法。但是我(通常)面临类型相关的问题。这是我的解析函数:
myParser :: (Stream s m Char) => ParsecT s (ShiftedState u s) m String
myParser = do
s <- P.getParserState
let i = stateInput s
let x = uncons i
return ""
并且出现以下错误。
Could not deduce (Stream s m0 Char)
arising from a use of ‘uncons’
问题是,我完全不知道错误的确切含义。我认为uncons
在基础单子中运行,而不在ParsecT单子中运行。但是我不知道该怎么举起(?)。
基本上,我想知道如何使用uncons
并从流中读取。现在请不要担心是否应该执行此操作...这基本上是我了解monad如何工作的xD
正在发生的事情:uncons
需要以某种形式运行。您可以通过其类型签名uncons :: Stream s m t => s -> m (Maybe (t, s))
看到它。但是,您只是在执行let x = uncons i
,因此x
是一个单子计算,它返回uncons i
的结果,但是您尚未指定运行该单子计算的哪个单子。 您偶然知道您要uncons i
在单子m
(满足Stream s m Char
)中运行,但是GHC并不知道。因此,GHC假设这里uncons i :: m0 (Maybe (t, s))
,其中m0
是任意的单子。因此,GHC会产生您看到的错误,因为uncons
要求满足约束Stream s m0 Char
才能使用它,但对于任何随机m0
不一定都必须满足该约束。
如何解决?好吧,您已经知道整个计算的类型为ParsecT s (ShiftedState u s) m Char
,并且m
满足实例Stream s m Char
。事实证明,有一个函数lift :: Monad m => m a -> ParsecT s u m a
可以将单峰计算lift :: Monad m => m a -> ParsecT s u m a
“提升”为Parsec计算m a
。因此,您只需将函数重写为:
ParsecT s u m a
我没有测试过,但是如果我没有犯任何错误,这应该可以工作。
((另一种解决方案是简单地给myParser :: (Stream s m Char) => ParsecT s (ShiftedState u s) m String
myParser = do
s <- P.getParserState
let i = stateInput s
x <- lift (uncons i)
return ""
一个类型签名:
x
这将强制let x :: m (Maybe (Char, s))
x = uncons i
具有所需的类型。现在,GHC可以看到x
和m
都满足相关约束,因此不会产生该错误。但这需要编译s
语言扩展,并且比以前的解决方案要优雅得多。)