haskell 秒差距的 (<|>) 运算符的行为?
behaviors of the (<|>) operator of haskell parsec?
我想用RPN解释器来练习Parsec的使用,下面是我的代码:
module RPN where
import Control.Applicative hiding((<|>))
import Text.ParserCombinators.Parsec
data RPNVal = Add|Sub|Mul|Div|Num Double deriving(Show)
a <:> b = (:) <$> a <*> b
a <++> b = (++) <$> a <*> b
opSymbol = oneOf "+-*/"
number = many1 digit :: Parser String
plus = char '+' *> number
minus = char '-' <:> number
integer = (number <|> minus <|> plus) :: Parser String
float = integer <++> decimal <++> exponent
where decimal = option "" $ char '.' <:> number
exponent = option "" $ oneOf "eE" <:> number
parseOp :: Parser RPNVal
parseOp = do
op <- opSymbol
case op of
'+' -> return Add
'-' -> return Sub
'*' -> return Mul
'/' -> return Div
parseNum :: Parser RPNVal
parseNum = liftA (read::String->Double) float >>= return.Num
parseRPNVal :: Parser RPNVal
-- parseRPNVal = parseOp <|> parseNum
-- parseRPNVal = parseNum <|> parseOp
parseRPNVal = try parseNum <|> parseOp
parseExpr :: Parser [RPNVal]
parseExpr = parseRPNVal `sepBy1` spaces
readExpr :: String->[RPNVal]
readExpr input = case parse parseExpr "RPN" input of
Left errMsg -> error $ show errMsg
Right val -> val
在parseRPNVal
的定义中,我发现如果我使用parseRPNVal = parseOp <|> parseNum
,那么解析器运行良好,但是,如果我使用parseRPNVal = parseNum <|> parseOp
,那么该函数只能解析数字而运算符会导致错误。
This operator behaves like this: it will first try the parser on the
left. If it consumed no input[35], it will try the parser on the right
谁能给我解释一下 parseOp
和 parseNum
的行为?
正如现实世界Haskell所说。
parseNum
先解析一个integer
,但是integer
-s可以加上+
或-
.
前缀
因此,在解析parseNum <|> parseOp
时,如果下一个字符是+
或-
,而我们实际拥有的是一个运算符,parseNum
读入那个字符之后才失败。
使用 parseOp <|> parseNum
,当然不需要回溯,因为 parseOp
只需要一个字符前瞻。
我想用RPN解释器来练习Parsec的使用,下面是我的代码:
module RPN where
import Control.Applicative hiding((<|>))
import Text.ParserCombinators.Parsec
data RPNVal = Add|Sub|Mul|Div|Num Double deriving(Show)
a <:> b = (:) <$> a <*> b
a <++> b = (++) <$> a <*> b
opSymbol = oneOf "+-*/"
number = many1 digit :: Parser String
plus = char '+' *> number
minus = char '-' <:> number
integer = (number <|> minus <|> plus) :: Parser String
float = integer <++> decimal <++> exponent
where decimal = option "" $ char '.' <:> number
exponent = option "" $ oneOf "eE" <:> number
parseOp :: Parser RPNVal
parseOp = do
op <- opSymbol
case op of
'+' -> return Add
'-' -> return Sub
'*' -> return Mul
'/' -> return Div
parseNum :: Parser RPNVal
parseNum = liftA (read::String->Double) float >>= return.Num
parseRPNVal :: Parser RPNVal
-- parseRPNVal = parseOp <|> parseNum
-- parseRPNVal = parseNum <|> parseOp
parseRPNVal = try parseNum <|> parseOp
parseExpr :: Parser [RPNVal]
parseExpr = parseRPNVal `sepBy1` spaces
readExpr :: String->[RPNVal]
readExpr input = case parse parseExpr "RPN" input of
Left errMsg -> error $ show errMsg
Right val -> val
在parseRPNVal
的定义中,我发现如果我使用parseRPNVal = parseOp <|> parseNum
,那么解析器运行良好,但是,如果我使用parseRPNVal = parseNum <|> parseOp
,那么该函数只能解析数字而运算符会导致错误。
This operator behaves like this: it will first try the parser on the left. If it consumed no input[35], it will try the parser on the right
谁能给我解释一下 parseOp
和 parseNum
的行为?
正如现实世界Haskell所说。
parseNum
先解析一个integer
,但是integer
-s可以加上+
或-
.
因此,在解析parseNum <|> parseOp
时,如果下一个字符是+
或-
,而我们实际拥有的是一个运算符,parseNum
读入那个字符之后才失败。
使用 parseOp <|> parseNum
,当然不需要回溯,因为 parseOp
只需要一个字符前瞻。