Parsing 如何在Haskell代码中实现用于整数处理的浮点解析器功能?
参考我的作业描述(我是一名只有Haskell基本经验的学生),我必须利用Text.Parsec制作一个简单的计算器解析器。到目前为止,程序只能通过整数值读取一些字符串输入来执行解析,例如:Parsing 如何在Haskell代码中实现用于整数处理的浮点解析器功能?,parsing,haskell,parsec,parser-combinators,Parsing,Haskell,Parsec,Parser Combinators,参考我的作业描述(我是一名只有Haskell基本经验的学生),我必须利用Text.Parsec制作一个简单的计算器解析器。到目前为止,程序只能通过整数值读取一些字符串输入来执行解析,例如: parseTest addition "5 + 8 / 4" 实际上,我有一个完整的程序代码: import Text.Parsec hiding(digit) import Data.Functor type CalcParser a = Parsec String () a digit :: Cal
parseTest addition "5 + 8 / 4"
实际上,我有一个完整的程序代码:
import Text.Parsec hiding(digit)
import Data.Functor
type CalcParser a = Parsec String () a
digit :: CalcParser Char
digit = oneOf ['0'..'9']
number :: CalcParser Integer
number = read <$> many1 digit
fp_char :: CalcParser String
fp_char = many1 digit
applyMany :: a -> [a -> a] -> a
applyMany x [] = x
applyMany x (h:t) = applyMany (h x) t
div_ :: CalcParser (Integer -> Integer -> Integer)
div_= do
char '/'
return div
star :: CalcParser (Integer -> Integer -> Integer)
star = do
char '*'
return (*)
plus :: CalcParser (Integer -> Integer -> Integer)
plus = do
char '+'
return (+)
minus :: CalcParser (Integer -> Integer -> Integer)
minus = do
char '-'
return (-)
multiply :: CalcParser Integer
multiply = do
spaces
lhv <- enclosed
spaces
t <- many tail
return $ applyMany lhv t
where tail =
do
f <- star <|> div_
spaces
rhv <- enclosed
spaces
return (`f` rhv)
add :: CalcParser Integer
add = do
spaces
lhv <- multiply <|> fact' <|> negation'
spaces
t <- many tail
return $ applyMany lhv t
where tail =
do
f <- plus <|> minus
spaces
rhv <- multiply <|> fact' <|> negation'
spaces
return (`f` rhv)
enclosed :: CalcParser Integer
enclosed = number <|> do
char '('
res <- add
char ')'
return res
-- factorial
fact' :: CalcParser Integer
fact' = do
spaces
char '!'
rhv <- number
return $ factorial rhv
factorial :: Integer -> Integer
factorial n
| n < 0 = error "No factorial exists for negative inputs"
| n == 0 || n == 1 = 1
| otherwise = acc n 1
where
acc 0 a = a
acc b a = acc (b-1) (b * a)
-- negation
negation' :: CalcParser Integer
negation' = do
spaces
char '~'
rhv <- enclosed
spaces
return $ negate rhv
我输入“!”在阶乘表示法的数字部分之前输入字符,因为解析器似乎无法识别正常的“4!”或类似的字符序列作为阶乘指示符 第1步:搜索并将所有出现的
整数
替换为双精度
。现在您的解析器仍然只能读取整数,但在内部它将它们表示为Double
s
第2步:使数字
解析器解析整数或浮点数。你已经记下的整数:它只是一个数字序列。让我们将其重命名,以更好地反映其功能:
parseInt :: CalcParser Double
parseInt = read <$> many1 digit
parseInt::CalcParser-Double
parseInt=读取多个1位数
浮点并不难:它是一个数字序列,后跟一个点(句点),后跟另一个数字序列:
parseDouble :: CalcParser Double
parseDouble = do
whole <- many1 digit
char '.'
fract <- many1 digit
pure $ read $ whole <> "." <> fract
parseDouble::CalcParser-Double
parseDouble=do
整体而不是试图同时支持整数和浮点,只需将其更改为只支持浮点即可。整数是双精度的子集(对于大小小于2^52的整数),因此这不会阻止您计算1+2
您的解析器坚持使用“!4”而不是“4!”,因为它就是这么说的。查看事实'
。它首先解析“!”然后解析数字。试着换一下。@Paul Johnson,谢谢你,你的便条是正确的。然而,我首先(在发布此问题之前)尝试解析“4!”,将char.
放在rhvtry parseDouble parseInt
下是编写解析器的一种方便方法,但它也会增加大量开销,并使生成有用的错误消息变得更加困难。这种方法的非家庭作业版本通过解析一个数字,后跟一个可选的小数部分,可以避免回溯并将数字重新读取为整数efficiency@Fyodor索伊金,当然,你的解释方法非常有力,能够抓住这个问题,非常感谢。现在我明白了要做什么和为什么,回答得很好。
parseDouble :: CalcParser Double
parseDouble = do
whole <- many1 digit
char '.'
fract <- many1 digit
pure $ read $ whole <> "." <> fract
number :: CalcParser Double
number = try parseDouble <|> parseInt