如何直接访问 Parsecs 输入流
How to access Parsecs Input Stream directly
我想直接访问 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
在底层 monad 中运行,而不是在 ParsecT monad 中运行。但是我不知道怎么解除(?)它。
基本上我想知道如何使用 uncons
并从流中读取。现在请不要担心 是否应该 这样做...这基本上是我对 monads 工作原理的理解 xD
这是正在发生的事情:uncons
需要在某种 monad 中 运行。您可以通过其类型签名看到这一点:uncons :: Stream s m t => s -> m (Maybe (t, s))
。但是你只是在做 let x = uncons i
—— 所以 x
是一个单子计算,returns 是 uncons i
的结果,但你没有指定 哪个 monad 这个monadic计算在运行ning里面。 你碰巧知道你“想要”uncons i
到运行在你的monad m
(满足Stream s m Char
),但是GHC不知道这个。所以 GHC 假设这里 uncons i :: m0 (Maybe (t, s))
,其中 m0
是一些任意的单子。因此 GHC 会产生您看到的错误,因为 uncons
需要满足约束 Stream s m0 Char
才能使用它,但是对于任何随机 m0
.[= 不一定满足该约束。 37=]
如何解决?好吧,您已经知道整个计算的类型是 ParsecT s (ShiftedState u s) m Char
,并且 m
满足实例 Stream s m Char
。事实证明,有一个函数 lift :: Monad m => m a -> ParsecT s u m a
可以将单子计算 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
这会强制 x
具有您想要的类型。现在 GHC 可以查看 m
和 s
都满足相关约束,因此不会产生该错误。但这需要 ScopedTypeVariables
语言扩展来编译,并且比以前的解决方案要优雅得多。)
我想直接访问 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
在底层 monad 中运行,而不是在 ParsecT monad 中运行。但是我不知道怎么解除(?)它。
基本上我想知道如何使用 uncons
并从流中读取。现在请不要担心 是否应该 这样做...这基本上是我对 monads 工作原理的理解 xD
这是正在发生的事情:uncons
需要在某种 monad 中 运行。您可以通过其类型签名看到这一点:uncons :: Stream s m t => s -> m (Maybe (t, s))
。但是你只是在做 let x = uncons i
—— 所以 x
是一个单子计算,returns 是 uncons i
的结果,但你没有指定 哪个 monad 这个monadic计算在运行ning里面。 你碰巧知道你“想要”uncons i
到运行在你的monad m
(满足Stream s m Char
),但是GHC不知道这个。所以 GHC 假设这里 uncons i :: m0 (Maybe (t, s))
,其中 m0
是一些任意的单子。因此 GHC 会产生您看到的错误,因为 uncons
需要满足约束 Stream s m0 Char
才能使用它,但是对于任何随机 m0
.[= 不一定满足该约束。 37=]
如何解决?好吧,您已经知道整个计算的类型是 ParsecT s (ShiftedState u s) m Char
,并且 m
满足实例 Stream s m Char
。事实证明,有一个函数 lift :: Monad m => m a -> ParsecT s u m a
可以将单子计算 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
这会强制 x
具有您想要的类型。现在 GHC 可以查看 m
和 s
都满足相关约束,因此不会产生该错误。但这需要 ScopedTypeVariables
语言扩展来编译,并且比以前的解决方案要优雅得多。)