我正在为自己编写一个计划,并对this page的练习4感到震惊。
我该如何解决这个问题?我已经走到了这一步,但不知道readHex
应该去哪里,我必须liftM
吗?你的案例与解析器匹配吗?
parseNumber = liftM (Number . read) $ choice [many1 digit, char '#' >> oneOf "hd" >>= a]
where a f = case f of
'h' -> many1 digit
另外,我不认为你可以在<|>
函数上应用Parser LispVal
,对吗?
答案 0 :(得分:2)
我已经走到了这一步,但不知道readHex应该去哪里,我必须解除它吗?
是的,因为readHex
很可能是纯函数,liftM
将其提升到Parser
的monadic上下文中。
由于我不太了解您的本地函数a
有什么用处,我暂时离开它并只使用函数parseDecimal
和parseHex
。在这种情况下,您可以这样写parseNumber
:
parseNumber :: Parser LispVal
parseNumber = liftM Number $ parseDecimal <|> parseHex
where parseDecimal :: Parser Integer
parseDecimal = liftM read $ many1 digit
parseHex :: Parser Integer
parseHex = liftM readHex $ char '#' >> ... -- parse hex value
当然你可以省略类型签名,为了清楚起见,我只是添加了它们。
此外,我不认为你可以申请&lt; |&gt;在Parser LispVal函数上,对吧?
<|>
适用于每个Parser a
。
我建议在解析器组合器上阅读一些材料,即Parsec User Guide。
答案 1 :(得分:1)
我稍微改变了布局,但这是我们正在考虑的代码示例:
parseNumber =
liftM (Number . read) $
choice [many1 digit, char '#' >> oneOf "hd" >>= a]
where
a f =
case f of
'h' -> many1 digit
我认为你在知道事情应该如何结合之前,试图同时做太多事情。您不得不将readHex
移动到(Number . read)
部分而不是read
,具体取决于正在读取的数字类型。
这是一个十六进制数的解析器,它不使用liftM
或其他奇特的组合器:
parseHex :: Parser LispVal
parseHex = do
char '#'
char 'x'
digits <- many1 hexDigit -- hexDigit is defined by Parsec.
return (Number (fst (readHex digits !! 0)))
这里棘手的部分是提取readHex
的结果。
您可以将解析器与
组合使用try parseHex <|> try parseOct <|> ... <|> parseDec
或者喜欢Parsec的调优和内联以及许多工具。但我从基础开始。