【问题标题】:How to express parsing logic in Parsec ParserT monad如何在 Parsec ParserT monad 中表达解析逻辑
【发布时间】:2016-08-22 02:12:41
【问题描述】:

我正在研究“在 48 小时内为自己编写一个方案”来学习 Haskell,但我遇到了一个我不太了解的问题。这是this section底部练习中的问题2。

任务是重写

import Text.ParserCombinators.Parsec
parseString :: Parser LispVal
parseString = do
                char '"'
                x <- many (noneOf "\"")
                char '"'
                return $ String x

这样正确转义的引号(例如,在“This sentence \” is nonsense”中)被解析器接受。

在命令式语言中,我可能会写出类似这样的东西(大致是 Python 的伪代码):

def parseString(input): 
  if input[0] != "\"" or input[len(input)-1] != "\"":
    return error
  input = input[1:len(input) - 1] # slice off quotation marks  
  output = "" # This is the 'zero' that accumulates over the following loop
  # If there is a '"' in our string we want to make sure the previous char
  # was '\'  

  for n in range(len(input)):
    if input[n] == "\"":
      try:
        if input[n - 1] != "\\":
          return error
      catch IndexOutOfBoundsError:
        return error
    output += input[n]
  return output

我一直在查看docs for Parsec,但我只是不知道如何将其用作一元表达式。

我明白了:

parseString :: Parser LispVal
parseString = do
                char '"'
                regular <- try $ many (noneOf "\"\\")
                quote <- string "\\\""
                char '"'
                return $ String $ regular ++ quote

但这仅适用于一个引号,并且它必须位于字符串的最后——我想不出一个函数表达式来完成我的循环和 if 语句在命令式伪代码中所做的工作.

感谢您抽出宝贵时间阅读本文并给我建议。

【问题讨论】:

    标签: parsing haskell functional-programming monads parsec


    【解决方案1】:

    试试这样的:

    dq :: Char
    dq = '"'
    
    parseString :: Parser Val
    parseString = do
      _ <- char dq
      x <- many ((char '\\' >> escapes) <|> noneOf [dq])
      _ <- char dq
      return $ String x
        where
          escapes = dq <$ char dq
                <|> '\n' <$ char 'n'
                <|> '\r' <$ char 'r'
                <|> '\t' <$ char 't'
                <|> '\\' <$ char '\\'
    

    【讨论】:

    • 旁白:x &gt;&gt; return aa &lt;$ x
    • 谢谢!我通过类型签名和文档来了解为什么x &gt;&gt; return aa &lt;$ x。有没有理由为什么后一种表达方式比前者更受欢迎? _ &lt;- char dqchar dq 更受青睐有什么原因吗? (已编辑)
    • &lt;$ 的表达式更短。至于_ &lt;- char dq,我在 48 小时内完成 Scheme 时复制了该代码。很明显,char dq 的值没有被使用。否则你会得到一个编译器警告(至少是-Wall)。
    • @lachrimae 对于任何遵守 monad 法则的类型,x &gt;&gt; return aa &lt;$ x 必须相等,因此在语义方面完全没有关系 - 显然后者可以节省您输入“return " n 次。
    【解决方案2】:

    解决方案是将字符串文字定义为起始引号 + 许多有效字符 + 结束引号,其中“有效字符”是转义序列或非引号。

    所以parseString有一行更改:

    parseString = do char '"'
                     x <- many validChar
                     char '"'
                     return $ String x
    

    我们添加定义:

    validChar = try escapeSequence <|> satisfy ( /= '"' )
    escapeSequence = do { char '\\'; anyChar }
    

    escapeSequence 可以改进以允许有限的转义序列集。

    【讨论】:

      猜你喜欢
      • 2020-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      相关资源
      最近更新 更多