这个问题似乎是this question的翻版,然而,自2012年以来,Parsec或缩进库都发生了变化,我为indent库找到的旧示例都没有编译到最新版本。
我想为一种编程语言制作一个解析器,其中缩进是语法的一部分(用于指示作用域),为了实现这一点,我想使用Text.Parsec.Indent库,但我对如何使用它感到困惑。对我来说,很明显,必须进行一些修改/自定义解析器类型,但我对State monad的有限了解和对parsec的表面理解似乎还不够。
假设您想为一个简单的int列表创建一个解析器,如下所示。如何做到这一点呢?
mylist
fstitem
snditem我试图基于互联网上流传的一些老例子创建一个简单的解析器,看起来像这样,但它显然会产生一些类型错误:
import Control.Monad.State
import Text.Parsec hiding (State)
import Text.Parsec.Indent
import Text.Parsec.Pos
type IParser a = ParsecT String () (State SourcePos) a
parseInt :: IParser Integer
parseInt = read <$> many1 digit
parseIndentedInt :: IParser Integer
parseIndentedInt = indented *> parseInt具体地说:
Frontend/Parser.hs:14:20: error:
• Couldn't match type ‘Control.Monad.Trans.Reader.ReaderT
Text.Parsec.Indent.Internal.Indentation m0’
with ‘StateT SourcePos Data.Functor.Identity.Identity’
Expected type: IParser Integer
Actual type: ParsecT String () (IndentT m0) Integer
• In the expression: indented *> parseInt
In an equation for ‘parseIndentedInt’:
parseIndentedInt = indented *> parseInt
|
14 | parseIndentedInt = indented *> parseInt
| ^^^^^^^^^^^^^^^^^^^^
Frontend/Parser.hs:14:32: error:
• Couldn't match type ‘StateT
SourcePos Data.Functor.Identity.Identity’
with ‘Control.Monad.Trans.Reader.ReaderT
Text.Parsec.Indent.Internal.Indentation m0’
Expected type: ParsecT String () (IndentT m0) Integer
Actual type: IParser Integer
• In the second argument of ‘(*>)’, namely ‘parseInt’
In the expression: indented *> parseInt
In an equation for ‘parseIndentedInt’:
parseIndentedInt = indented *> parseInt
|
14 | parseIndentedInt = indented *> parseInt
| ^^^^^^^^
Failed, no modules loaded.发布于 2021-06-25 22:04:11
好的,在深入研究了源代码并查看了缩进GitHub存储库中的测试之后,我设法创建了一个工作示例。
下面的代码可以解析一个简单的缩进列表:
import Text.Parsec as Parsec
import Text.Parsec.Indent as Indent
data ExampleList = ExampleList String [ExampleList]
deriving (Eq, Show)
plistItem :: Indent.IndentParser String () String
plistItem = Parsec.many1 Parsec.lower <* Parsec.spaces
pList :: Indent.IndentParser String () ExampleList
pList = Indent.withPos (ExampleList <$> plistItem <*> Parsec.many (Indent.indented *> pList))
useParser :: Indent.IndentParser String () a -> String -> a
useParser p src = helper res
where res = Indent.runIndent $ Parsec.runParserT (p <* Parsec.eof) () "<test>" src
helper (Left err) = error "Parse error"
helper (Right ok) = ok示例用法:
*Main> useParser pList "mylist\n\tfstitem\n\tsnditem"
ExampleList "mylist" [ExampleList "fstitem" [],ExampleList "snditem" []]请注意,useParser函数做了一些工作,实际获取来自任一单数的结果,以及将文件末尾解析器放在所提供的解析器后面。根据您的应用程序,您可能想要更改此设置。
此外,类型签名可以是这样的缩写:
type IParser a = Indent.IndentParser String () a
plistItem :: IParser String
pList :: IParser ExampleList
useParser :: IParser a -> String -> ahttps://stackoverflow.com/questions/68130972
复制相似问题