2013-03-13 61 views
0

我剛開始學習用秒差距解析字符串,我面臨着以下的問題,我不能去繞到我的腦海:秒差距解析器:自定義失敗在一定條件下不計算

以下代碼包含三個解析器運行,其中兩個顯然會失敗。奇怪的是,我的自定義失敗消息只會在第二次運行時發生,而不會發生在第三次。

import Text.Parsec 
import Text.Parsec.String 

ps :: Parser String 
ps = (string "123") <|> (string "456") <|> fail "my-failure" 

main = do 
    putStrLn $ "A: " ++ show (parse ps "" "123") 
    putStrLn $ "\nB: " ++ show (parse ps "" "789") 
    putStrLn $ "\nC: " ++ show (parse ps "" "45x") 

輸出:

A: Right "123" 

B: Left (line 1, column 1): 
unexpected "7" 
expecting "123" or "456" 
my-failure 

C: Left (line 1, column 1): 
unexpected "x" 
expecting "456" 

是什麼讓我的失敗消息出現總是當第二<|>的部分左側失敗的正確方法是什麼?我可以覆蓋以前發生的任何錯誤嗎?

回答

8

Parsec中的<|>組合器只在分析器不消耗任何輸入時嘗試下一個選項。在你的情況下,解析器string "456"匹配"45x"的開頭,因此不再嘗試其他替代方法。如果您需要任意預覽,則需要使用try函數。

ps :: Parser String 
ps = string "123" <|> try (string "456") <|> fail "my-failure" 

<|>秒差距的文檔:

這個組合子實現的選擇。解析器p首先應用p。如果成功,則返回p的值。如果p沒有消耗任何輸入而失敗,則嘗試解析器q。該組合器的定義與MonadPlus類的mplus成員和Alternative的(< |>)成員相同。

解析器被稱爲預測性的,因爲只有在解析器p 沒有消耗任何輸入(即前面的觀察值爲1)時才嘗試q。這種非回溯行爲允許解析器組合器的高效實現 以及良好錯誤消息的生成。

+2

取代'<|>不合格 「我的失敗」'你可能更願意使用[''(http://hackage.haskell.org/packages/archive/parsec/latest/doc/html/Text -Parsec-Prim.html#v:-60--63--62-),如'「語法元素」',它將產生錯誤信息'expectcting syntax element'而不是'my-failure'。但是你仍然需要使用'try'。 – Beetle 2013-03-13 18:20:13