我想做一個簡單的決議器來決議加法運算式。這是我的代碼:
import Text.Parsec.Char
import Text.Parsec.String
import Text.ParserCombinators.Parsec
data Expr = Number Float |
Add Expr Expr |
number :: Parser Expr
number = do
n <- try $ many1 digit
return $ Number $ read n
add :: Parser Expr
add = do
e1 <- number
char ' '
e2 <- number
return $ Add e1 e2
expr :: Parser Expr
expr = try number <|> try add
p :: String -> Either ParseError Expr
p = parse (do{e <- expr; eof; return e}) "error"
但這是輸出
ghci> parse add "err" "1 2"
Right (Add (Number 1.0) (Number 2.0))
ghci> p "1"
Right (Number 1.0)
ghci> p "1 2"
Left "error" (line 1, column 2):
unexpected ' '
expecting digit or end of input
但是如果我將expr組合器的順序更改為
expr :: Parser Expr
expr = try add <|> try number
然后輸出變為
ghci> p "1 2"
Right (Add (Number 1.0) (Number 2.0))
為什么會這樣?我認為try關鍵字會強制我組合的決議器在每個<|>.
我計劃把它做得更大,所以我想確定我理解為什么現在會發生這種情況。
我的實際程式已經更大了,但這仍然獨立地引起問題。
uj5u.com熱心網友回復:
您面臨的問題是,當使用"1 2"決議字串時number,它會成功(誠然,有一些未決議的字符)。try只有在失敗時才使用。
或許另一種說明這一點的方式是考慮這個例子try (string "a") <|> try (string "ab")。這將成功匹配任何以字符開頭的字串a,但它永遠不會匹配以 開頭的字串"ab"。
如果您嘗試過
exprAll :: Parser Expr
exprAll = try (number <* eof) <|> try (add <* eof)
那么你可能會得到你正在尋找的行為。在這種情況下,“try”d 決議器在到達檔案結尾字符之前不會成功,因此當 遇到 時,決議嘗試number <* eof失敗,然后使用 重新開始決議add <* eof。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/532466.html
標籤:哈斯克尔秒差距
上一篇:Haskell串列的高階過濾函式
