Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing Haskell/Parsec:如何使用Text.Parsec.Indent中的函数?_Parsing_Haskell_Indentation_Parsec - Fatal编程技术网

Parsing Haskell/Parsec:如何使用Text.Parsec.Indent中的函数?

Parsing Haskell/Parsec:如何使用Text.Parsec.Indent中的函数?,parsing,haskell,indentation,parsec,Parsing,Haskell,Indentation,Parsec,我很难理解如何使用Haskell包提供的模块中的任何函数,Haskell包是Parsec的一种附加组件 所有这些函数都做什么?如何使用它们 我可以理解withBlock的简短黑线鳕描述,并且我找到了如何使用withBlock、runIndent和IndentParser类型的示例,以及。我还可以理解四个解析器的文档。但是很多事情仍然让我困惑 特别是: 带f a p块的和 do aa <- a pp <- block p return f aa pp do aa因此,第一

我很难理解如何使用Haskell包提供的模块中的任何函数,Haskell包是Parsec的一种附加组件

所有这些函数都做什么?如何使用它们

我可以理解
withBlock
的简短黑线鳕描述,并且我找到了如何使用
withBlock
runIndent
IndentParser
类型的示例,以及。我还可以理解四个解析器的文档。但是很多事情仍然让我困惑

特别是:

  • 带f a p块的

    do aa <- a
       pp <- block p
       return f aa pp
    

    do aa因此,第一个提示是查看
    IndentParser

    type IndentParser s u a = ParsecT s u (State SourcePos) a
    
    也就是说,它是一个
    ParsecT
    额外密切监视的抽象容器,可用于访问当前列号等内容。因此,它可能将当前的“缩进级别”存储在
    SourcePos
    中。这是我对“参考水平”的初步猜测

    简而言之,
    indents
    为您提供了一种新的
    Parsec
    ,它对上下文特别敏感,对当前缩进非常敏感。我会按顺序回答你的问题


    (2) “引用级别”是这个缩进级别开始的当前解析器上下文状态中引用的“信念”。为了更清楚,让我给出一些关于(3)的测试用例

    (3) 为了开始试验这些函数,我们将构建一个小的测试运行程序。它将使用我们提供的字符串运行解析器,然后使用我们要修改的
    initialPos
    打开内部
    状态
    部分。编码

    import Text.Parsec
    import Text.Parsec.Pos
    import Text.Parsec.Indent
    import Control.Monad.State
    
    testParse :: (SourcePos -> SourcePos) 
              -> IndentParser String () a 
              -> String -> Either ParseError a
    testParse f p src = fst $ flip runState (f $ initialPos "") $ runParserT p () "" src
    
    (注意这几乎是
    runIndent
    ,除了我提供了一个后门来修改
    initialPos

    现在我们可以看一下缩进的
    。通过检查源代码,我可以看出它做了两件事。首先,如果当前
    SourcePos
    列号小于或等于
    SourcePos
    中存储的
    State
    中的
    SourcePos
    中存储的“参考级别”,它将
    失败。其次,它有点神秘地将
    状态
    SourcePos
    的行计数器(而不是列计数器)更新为当前状态

    据我所知,只有第一种行为才是重要的。我们可以看到这里的区别

    >>> testParse id indented ""
    Left (line 1, column 1): not indented
    
    >>> testParse id (spaces >> indented) "   "
    Right ()
    
    >>> testParse id (many (char 'x') >> indented) "xxxx"
    Right ()
    
    因此,为了使
    缩进成功,我们需要使用足够的空白(或任何其他!)来将列位置推过“reference”列位置。否则,它将无法说出“未缩进”。接下来的三个函数也存在类似的行为:
    same
    失败,除非当前位置和参考位置在同一行上;
    sameOrIndented
    失败,如果当前列严格小于参考列,除非它们在同一行上,除非当前列和引用列匹配,否则检查缩进将失败

    与pos
    略有不同。它不仅仅是一个
    IndentParser
    ,它是一个
    IndentParser
    -组合器它将输入
    IndentParser
    转换为一个认为“引用列”(处于
    状态的
    SourcePos
    )正是我们调用
    with pos
    时的位置

    顺便说一句,这给了我们另一个提示。它让我们知道我们有权更改引用列

    (1)现在,让我们来看看<代码>块和<代码>如何使用我们的新的、低级引用列运算符使用Bug < /Cord>工作。code>withBlock

    是根据
    block
    实现的,因此我们将从
    block
    开始

    -- simplified from the actual source
    block p = withPos $ many1 (checkIndent >> p)
    
    因此,
    block
    将“参考列”重置为当前列的任何内容,然后使用来自
    p
    的至少1个解析,只要每个解析与新设置的“参考列”缩进相同。现在我们可以用block查看

    withBlock f a p = withPos $ do
      r1 <- a
      r2 <- option [] (indented >> block p)
      return (f r1 r2)
    
    withBlock f a p=withPos$do
    r1(p区)
    返回(f r1 r2)
    
    因此,它将“参考列”重置为当前列,解析单个
    a
    parse,尝试解析
    p
    s的
    缩进的
    ,然后使用
    f
    组合结果。您的实现几乎是正确的,只是需要使用
    with pos
    来选择正确的“参考列”

    然后,一旦你有了
    withBlock
    withBlock'=withBlock(\\ubs->bs)

    (5) 因此,
    indented
    和friends正是执行此操作的工具:如果解析相对于
    withPos
    选择的“参考位置”缩进不正确,它们将导致解析立即失败

    (4) 是的,在你学会如何在base
    Parsec
    中使用解析之前,不要担心这些家伙。它通常是一种更干净、更快、更简单的指定解析的方法。有时它们甚至更强大,但如果你理解Monad,那么它们几乎总是完全相同的

    (6) 这是关键。如果您可以使用
    with pos
    描述您的预期缩进,那么到目前为止提到的工具只能导致缩进失败。很快,我认为不可能根据其他解析的成功或失败来指定
    with pos
    。。。所以你必须再深入一层。幸运的是,
    IndentParser
    s工作的机制很明显,它只是一个内部
    状态
    monad,包含
    SourcePos
    。您可以使用
    lift::MonadTrans t=>ma->tma
    来操作此内部状态,并根据需要设置“参考列”


    干杯

    你看过源代码了吗?(按照文档中类型签名右侧的“源”链接)这至少对您的第一个问题有帮助。对不起,还有一个问题。什么事