代码之家  ›  专栏  ›  技术社区  ›  davetapley

Haskell:将reads函数提升到parsec解析器

  •  4
  • davetapley  · 技术社区  · 15 年前

    here 我想使用 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
    

    有人能就以下方面对这种方法提出改进意见吗

  • 你会同意这个条件吗 (f s) 被记录下来,或者在一个案例中被评估两次 null (f s) 返回 False ?
  • 处理多个成功的解析,即 length (f s) 大于1,我不知道parsec如何处理这个问题。
  • (snd . head) (f s) .
  • 2 回复  |  直到 14 年前
        1
  •  3
  •   recursion.ninja    10 年前

    这是个好主意。更自然的方法 你的 ReadS parser更适合Parsec Parser String 在类型的开头:

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

    这种“combinator”风格是非常地道的Haskell-一旦你 习惯了它,函数定义就容易多了 阅读和理解。

    然后你会使用 liftReadS 在这个简单的例子中:

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

    (注意 listToMaybe 是在 Data.Maybe

    在更复杂的情况下, 升降踏板 帕塞克 do 阻止。

    1. reader 现在只应用了一次,所以没有什么可以“记忆”的。
    2. 通常和公认的做法是忽略 阅读 在大多数情况下,你很好。
        2
  •  0
  •   dave4420    15 年前

    回答你问题的第一部分,不 (f s)

    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
    
    推荐文章