Haskell:将读取函数提升到秒差距解析器
作为第四个练习的一部分此处 我想使用 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:
(f s)
be memoised, or evaluated twice in the case of a null (f s)
returning False
?length (f s)
is greater than one, I do not know how parsec deals with this.(snd . head) (f s)
.如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是个好主意。一种更自然的方法可以使
你的 ReadS 解析器更适合 Parsec 是
在类型的开头省略
Parser String
:这种“组合器”风格是非常惯用的 Haskell - 一旦你
习惯它,它使函数定义变得更容易
阅读和理解。
然后,在简单的情况下,您可以像这样使用
liftReadS
:(请注意,
listToMaybe
位于Data.Maybe
模块中。)在更复杂的情况下,
liftReadS
易于在任何内部使用秒差距
do
块。关于您的其他一些问题:
reader
现在仅应用一次,因此没有什么可以“记忆”的。This is a nice idea. A more natural approach that would make
your
ReadS
parser fit in better with Parsec would be toleave off the
Parser String
at the beginning of the type: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:(Note that
listToMaybe
is in theData.Maybe
module.)In more complex cases,
liftReadS
is easy to use inside anyParsec
do
block.Regarding some of your other questions:
reader
is applied only once now, so there is nothing to "memoize".ReadS
parser in most cases, so you're fine.要回答问题的第一部分,不会记住
(fs)
,您必须手动执行此操作:但我会使用模式匹配:
To answer the first part of your question, no
(f s)
will not be memoised, you would have to do that manually:But I'd use pattern matching instead: