Parsing Haskell:将reads函数提升到parsec解析器
作为第四个练习的一部分 我想将Parsing Haskell:将reads函数提升到parsec解析器,parsing,haskell,parsec,Parsing,Haskell,Parsec,作为第四个练习的一部分 我想将reads类型函数(如readHex)与parsec解析器一起使用 为此,我编写了一个函数: 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
reads
类型函数(如readHex
)与parsec解析器一起使用
为此,我编写了一个函数:
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)
要回答问题的第一部分,不会记录任何(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
这是个好主意。一个更自然的方法会使
您的读取
解析器更适合使用Parsec
在类型的开头,不使用解析器字符串
:
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"
(请注意,listtomabe
位于数据中。可能是模块。)
在更复杂的情况下,liftReadS
在任何应用程序中都很容易使用
Parsecdo
块
关于您的其他一些问题:
功能读卡器
现在只应用一次,因此没有什么可“记忆”的
在大多数情况下,除了读取的解析器中的第一个解析之外,忽略所有解析都是一种常见且公认的做法,因此您很好
非常好,我不知道为什么我不想传入字符串
,也感谢您提醒我有关maybe
函数的信息。这似乎很相关: