如何直接访问Parsecs输入流

问题描述 投票:0回答:1

我想直接使用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

haskell parsec
1个回答
0
投票

正在发生的事情: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可以看到xm都满足相关约束,因此不会产生该错误。但这需要编译s语言扩展,并且比以前的解决方案要优雅得多。)

© www.soinside.com 2019 - 2024. All rights reserved.