Parsing Haskell/Parsec:如何将Text.Parsec.Token与Text.Parsec.Indent一起使用(来自indents包)
Haskell的Parsec的indents包提供了一种解析缩进风格语言(如Haskell和Python)的方法。它重新定义了Parsing Haskell/Parsec:如何将Text.Parsec.Token与Text.Parsec.Indent一起使用(来自indents包),parsing,haskell,types,indentation,parsec,Parsing,Haskell,Types,Indentation,Parsec,Haskell的Parsec的indents包提供了一种解析缩进风格语言(如Haskell和Python)的方法。它重新定义了解析器类型,那么如何使用由Parsec模块导出的令牌解析器函数,这些函数属于正常的解析器类型 背景 是一个解析器组合器库,不管这意味着什么 是一个提供两个模块和 是提供单个模块的新软件包 Parsec随附。它们中的大多数导出一组有用的解析器(例如,newlinefrom,用于解析新行)或解析器组合器(例如,countnpfrom,用于运行解析器p,n次) 但是,模块希
解析器
类型,那么如何使用由Parsec模块导出的令牌解析器函数,这些函数属于正常的解析器
类型
背景
- 是一个解析器组合器库,不管这意味着什么
- 是一个提供两个模块和
- 是提供单个模块的新软件包
newline
from,用于解析新行)或解析器组合器(例如,countnp
from,用于运行解析器p,n次)
但是,模块希望导出由用户使用所分析语言的功能参数化的函数,例如,大括号p
函数将在解析“{”之后和解析“}”之前运行解析器p,忽略注释之类的内容,注释的语法取决于您的语言
实现这一点的方法是,它导出一个函数,您调用该函数,为其提供特定语言的参数(如注释的外观),然后返回一条记录,其中包含中的所有函数,并根据指定的语言进行调整
当然,在缩进风格的语言中,这些需要进一步调整(也许?这里我不确定-我稍后会解释),所以我注意到,它提供了一个模块,看起来可以替代
我应该在某一点上提到,所有的Parsec解析器都是一元函数,因此它们对state做了一些神奇的事情,这样错误消息就可以说错误出现在源文件的哪一行和哪一列
我的问题
出于几个小原因,我觉得它或多或少是IndentParser的当前版本,但是它没有提供类似的模块,它只提供Text.Parsec.Indent
,因此我想知道如何从Text.Parsec.token
获取所有令牌解析器(比如reserved“something”
解析保留关键字“something”,或者像我前面提到的brages
)
在我看来,(新的)Text.Parsec.Indent
通过某种一元状态魔法来计算源代码的列位,因此它不需要修改像whiteSpace
from这样的标记解析器,这可能就是它不提供替换模块的原因。但我在类型方面有问题
你看,如果没有Text.Parsec.Indent
,我所有的解析器都是Parser Something
类型,其中Something是返回类型,Parser
是Text.Parsec.String中定义的类型别名
type Parser = Parsec String ()
但是对于Text.Parsec.Indent
,我使用自己的定义,而不是导入Text.Parsec.String
type Parser a = IndentParser String () a
这使得我所有的IndentParser String()类型的解析器都成为了某种东西,其中IndentParser是在Text.Parsec.Indent中定义的。但是我从Text.Parsec.token
中得到的令牌解析器的类型是错误的
如果到目前为止这还没有什么意义,那是因为我有点迷路了。类型问题是
我得到的错误是,我试图用另一个替换上面的解析器
的一个定义,但是当我试图使用Text.Parsec.token
中的一个令牌解析器时,我得到了编译错误
Couldn't match expected type `Control.Monad.Trans.State.Lazy.State
Text.Parsec.Pos.SourcePos'
with actual type `Data.Functor.Identity.Identity'
Expected type: P.GenTokenParser
String
()
(Control.Monad.Trans.State.Lazy.State Text.Parsec.Pos.SourcePos)
Actual type: P.TokenParser ()
链接
- (旧包装)
- ,提供Text.Parsec.Indent(新包)
- 使用示例代码
遗憾的是,上面的两个示例都没有像Text.Parsec.token中那样使用令牌解析器。您想做什么?
听起来你想让你的解析器在任何地方都被定义为
Parser Something
(其中某物是返回类型)并通过隐藏和重新定义通常从Text.Parsec.String
或类似文件导入的Parser
类型来执行此操作。您仍然需要导入一些Text.Parsec.String
,以使流成为monad的实例;使用以下行执行此操作:
import Text.Parsec.String ()
您对解析器的定义是正确的。或者,您可以使用
import Control.Monad.State
import Text.Parsec.Pos (SourcePos)
type Parser = ParsecT String () (State SourcePos)
并可能在出现此定义的文件中删除导入Text.Parsec.Indent(IndentParser)
错误,墙上的错误
您的问题是您看到的编译器错误消息的错误部分
无法将预期类型“State SourcePos”与实际类型“Identity”匹配
当你应该专注于
预期类型:P.GenTokenParser。。。
实际类型:P.TokenParser。。。
它编译!
当您从Text.Parsec.Token
中“导入”解析器时,您实际要做的当然是(正如您简要提到的)首先定义一个记录您的语言参数,然后将其传递给函数makeTokenParser
,该函数返回一个包含令牌解析器的记录
因此,您必须有一些类似以下内容的行:
import qualified Text.Parsec.Token as P
beetleDef :: P.LanguageDef st
beetleDef =
haskellStyle {
parameters, parameters etc.
}
lexer :: P.TokenParser ()
lexer = P.makeTokenParser beetleDef
…但是p.LanguageDef st
只是一个GenLanguageDef字符串st标识
,而p.TokenParser()
实际上是一个GenTokenParser字符串()标识
必须将类型声明更改为以下内容:
import Control.Monad.State
import Text.Parsec.Pos (SourcePos)
import qualified Text.Parsec.Token as P
beetleDef :: P.GenLanguageDef String st (State SourcePos)
beetleDef =
haskellStyle {
parameters, parameters etc.
}
lexer :: P.GenTokenParser String () (State SourcePos)
lexer = P.makeTokenParser beetleDef
…就是这样!这将允许您的“导入的”令牌解析器具有类型ParsecT String()(State SourcePos)Something
,而不是Parsec String()Something
(它是ParsecT String()Identity Something
的别名),您的代码现在应该可以编译了