Parsing 如何使用Haskell Parsec阻止不一致的浮点输入?

Parsing 如何使用Haskell Parsec阻止不一致的浮点输入?,parsing,haskell,parsec,Parsing,Haskell,Parsec,我被指派使用Haskell解析器组合器(即,通过导入Parsec.Text)制作一个相当简单的计算器解析器。该解析器需要对整数和浮点输入进行操作。有一个基本的代码来介绍我正在寻找的东西: import Text.Parsec hiding(digit) import Data.Functor type Parser a = Parsec String () a digit :: Parser Char digit = oneOf ['0'..'9'] number :: Parser In

我被指派使用Haskell解析器组合器(即,通过导入Parsec.Text)制作一个相当简单的计算器解析器。该解析器需要对整数和浮点输入进行操作。有一个基本的代码来介绍我正在寻找的东西:

import Text.Parsec hiding(digit)
import Data.Functor

type Parser a = Parsec String () a

digit :: Parser Char
digit = oneOf ['0'..'9']

number :: Parser Integer
number = read <$> many1 digit

fp_char :: Parser String 
fp_char = many1 digit

fp_number :: Parser Double
fp_number = read <$> parser where
    parser = (++) <$> fp_char <*> (option "" $ (:) <$> char '.' <*> fp_char)   

addition :: Parser Integer
addition = do
    lhv <- number
    spaces
    char '+'
    spaces
    rhv <- number
    return $ lhv + rhv

fp_addition :: Parser Double
addition = do
    lhv <- fp_number
    spaces
    char '+'
    spaces
    rhv <- fp_number
    return $ lhv + rhv
两者都被认为是错误触发器,但在上面的代码中,它被证明接受了一部分错误输入:事实上,一旦出现错误字符(如字母),解析器就会丢弃它,后面的字符也会被删除。因此,当相同或相似的输入仍然是有效的输入数据时,问题就出现了,即使它部分消失了。我的解决方案与此功能有关:

isValidInput :: Parser String -> Bool
isValidInput (x:xs) = if x `elem` ['0'..'9'] then isValidInput xs else False

由于
isValidInput
导致类型不正确,因此无法工作。更重要的是,我不理解如何使用这个辅助代码将其添加到核心计算函数中,比如这里给出的fp_加法

作为一般规则,Parsec解析器应该写入以使用输入流的有效前缀,并在不识别的第一个字符处停止

因此,字符串
“123h.578”
应该由
fp\u number
number
成功解析,因为前缀
“123”
对于这些解析器来说是可接受的输入。因此,您现有的解析器
fp_number
number
具有正确的行为:

> parseTest fp_number "123h.578"
123.0      -- this is correct
> parseTest number "123h.578"
123        -- this is also correct
应在更高级别上检查此无效
h
字符。通常,您将拥有一个顶级解析器,该解析器尝试解析整个流,并使用
eof
解析器来确保不存在不可解析的字符。例如,解析器:

fp_expression :: Parser Double
fp_expression =
  (try fp_addition <|> fp_number) <* eof
在拒绝其他示例的同时:

> parseTest fp_expression "123h.578"
parse error at (line 1, column 4):
unexpected 'h'
expecting "." or end of input
> parseTest fp_expression "600.w57"
parse error at (line 1, column 5):
unexpected "w"
您不需要显式的
isValidInput
函数。如果要定义一个表达式,可能需要通过运行类似于
fp_expression
的解析器来实现,以查看它是否能够成功解析整个流


此外,你可能会发现学习有帮助。通读“非常简单的表达式解析”一章将帮助您学习编写这种解析器的基础知识

非常有力的回答,谢谢。我会用你们推荐的教程来提高我的理解力。
> parseTest fp_expression "123+0.578"
123.578
> parseTest fp_expression "123.578"
123.578
> parseTest fp_expression "123h.578"
parse error at (line 1, column 4):
unexpected 'h'
expecting "." or end of input
> parseTest fp_expression "600.w57"
parse error at (line 1, column 5):
unexpected "w"