Haskell:将读取函数提升到秒差距解析器

发布于 2024-09-16 03:51:04 字数 874 浏览 5 评论 0原文

作为第四个练习的一部分此处 我想使用 reads 类型函数,例如 readHex 和 parsec Parser

为此,我编写了一个函数:

liftReadsToParse :: Parser String -> (String -> [(a, String)]) -> Parser a
liftReadsToParse p f = p >>= \s -> if null (f s) then fail "No parse" else (return . fst . head ) (f s)

可以使用该函数,例如在 GHCI 中,如下所示:

*Main Numeric> parse (liftReadsToParse (many1 hexDigit) readHex) "" "a1"
Right 161

任何人都可以建议对此方法进行以下方面的任何改进:

  • 术语(fs)是否会被记忆,或者在null (fs)返回False的情况下被评估两次?
  • 处理多个成功的解析,即当length (fs)大于1时,我不知道parsec如何处理这个问题。
  • 处理解析的剩余部分,即 (snd . head) (fs).

  • As part of the 4th exercise here
    I would like to use a reads type function such as readHex with a parsec Parser.

    To do this I have written a function:

    liftReadsToParse :: Parser String -> (String -> [(a, String)]) -> Parser a
    liftReadsToParse p f = p >>= \s -> if null (f s) then fail "No parse" else (return . fst . head ) (f s)
    

    Which can be used, for example in GHCI, like this:

    *Main Numeric> parse (liftReadsToParse (many1 hexDigit) readHex) "" "a1"
    Right 161
    

    Can anyone suggest any improvement to this approach with regard to:

  • Will the term (f s) be memoised, or evaluated twice in the case of a null (f s) returning False?
  • Handling multiple successful parses, i.e. when length (f s) is greater than one, I do not know how parsec deals with this.
  • Handling the remainder of the parse, i.e. (snd . head) (f s).

  • 如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

    扫码二维码加入Web技术交流群

    发布评论

    需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

    评论(2

    如果没有 2024-09-23 03:51:04

    这是个好主意。一种更自然的方法可以使
    你的 ReadS 解析器更适合 Parsec 是
    在类型的开头省略 Parser String

    liftReadS :: ReadS a -> String -> Parser a
    liftReadS reader = maybe (unexpected "no parse") (return . fst) .
                       listToMaybe . filter (null . snd) . reader
    

    这种“组合器”风格是非常惯用的 Haskell - 一旦你
    习惯它,它使函数定义变得更容易
    阅读和理解。

    然后,在简单的情况下,您可以像这样使用 liftReadS:(

    > parse (many1 hexDigit >>= liftReadS readHex) "" "a1"
    

    请注意,listToMaybe 位于 Data.Maybe 模块中。)

    在更复杂的情况下, liftReadS 易于在任何内部使用
    秒差距 do 块。

    关于您的其他一些问题:

    1. 函数 reader 现在仅应用一次,因此没有什么可以“记忆”的。
    2. 在大多数情况下,忽略 ReadS 解析器中除第一个解析之外的所有解析是常见且可接受的做法,因此没问题。

    This is a nice idea. A more natural approach that would make
    your ReadS parser fit in better with Parsec would be to
    leave off the Parser String at the beginning of the type:

    liftReadS :: ReadS a -> String -> Parser a
    liftReadS reader = maybe (unexpected "no parse") (return . fst) .
                       listToMaybe . filter (null . snd) . reader
    

    This "combinator" style is very idiomatic Haskell - once you
    get used to it, it makes function definitions much easier
    to read and understand.

    You would then use liftReadS like this in the simple case:

    > parse (many1 hexDigit >>= liftReadS readHex) "" "a1"
    

    (Note that listToMaybe is in the Data.Maybe module.)

    In more complex cases, liftReadS is easy to use inside any
    Parsec do block.

    Regarding some of your other questions:

    1. The function reader is applied only once now, so there is nothing to "memoize".
    2. It is common and accepted practice to ignore all except the first parse in a ReadS parser in most cases, so you're fine.
    浴红衣 2024-09-23 03:51:04

    要回答问题的第一部分,不会记住 (fs) ,您必须手动执行此操作:

    liftReadsToParse p f = p >>= \s -> let fs = f s in if null fs then fail "No parse"
                                                                  else (return . fst . head ) fs
    

    但我会使用模式匹配:

    liftReadsToParse p f = p >>= \s -> case f s of
                                            []              -> fail "No parse"
                                            (answer, _) : _ -> return answer
    

    To answer the first part of your question, no (f s) will not be memoised, you would have to do that manually:

    liftReadsToParse p f = p >>= \s -> let fs = f s in if null fs then fail "No parse"
                                                                  else (return . fst . head ) fs
    

    But I'd use pattern matching instead:

    liftReadsToParse p f = p >>= \s -> case f s of
                                            []              -> fail "No parse"
                                            (answer, _) : _ -> return answer
    
    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文