【问题标题】:How to access Parsecs Input Stream directly如何直接访问 Parsecs 输入流
【发布时间】:2020-01-09 10:16:22
【问题描述】:

我想直接访问 parsecs 输入流,这可以使用 getParserState 完成。要从流中读取,提供了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 并从流中读取。现在请不要担心一个应该这样做......这基本上是我理解单子是如何工作的xD

【问题讨论】:

  • 发生了什么事:uncons 需要在某种 monad 中运行(看看the definition)。但是你只是在做let x = uncons i——所以x是一个返回uncons结果的单子计算,但是你没有指定哪个单子计算在其中运行。错误只是说,由于您没有指定 monad,它称为 m0,GHC 不一定知道 monad m0 是否实际上是 Stream s m0 Char 的实例。
  • (我没有将其发布为答案的原因是因为我还没有解决方案。但我想我现在有一个解决方案 - 我现在重新发布该评论作为答案.)

标签: haskell parsec


【解决方案1】:

这是发生了什么:uncons 需要在某种 monad 中运行。您可以通过其类型签名看到这一点:uncons :: Stream s m t =&gt; s -&gt; m (Maybe (t, s))。但是你只是在做let x = uncons i——所以x是一个单子计算,它返回uncons i的结果,但是你没有指定哪个这个单子计算在其中运行。 碰巧知道你“想要”uncons i 在你的 monad 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 =&gt; m a -&gt; ParsecT s u m a 可以将一元计算 m a “提升”为 Parsec 计算 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

这会强制x 具有您想要的类型。现在 GHC 可以查看并看到 ms 都满足相关约束,因此不会产生该错误。但这需要ScopedTypeVariables 语言扩展来编译,而且比之前的解决方案优雅得多。)

【讨论】:

    猜你喜欢
    • 2021-12-22
    • 2013-01-19
    • 2016-11-26
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    • 2014-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多