Parsing 如何在Haskell代码中实现用于整数处理的浮点解析器功能?

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

参考我的作业描述(我是一名只有Haskell基本经验的学生),我必须利用Text.Parsec制作一个简单的计算器解析器。到目前为止,程序只能通过整数值读取一些字符串输入来执行解析,例如:

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.
放在
rhv
try 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