我目前正在嘗試在 Parsec 中撰寫一個簡單的決議器,但一直遇到有關空格的問題:作為一個最小的例子,我有一個決議器可以決議兩個字母,兩個小寫或一個大寫和一個小寫。我會這樣做
testP :: Parser String
testP = do
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
a1 <- upper
a2 <- lower
return [a1,a2]
這對像“as”或“Bs”這樣的字串按預期作業。現在我想在輸入字串的開頭處理可能的空格。如果我做
testP :: Parser String
testP = do
spaces
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
a1 <- upper
a2 <- lower
return [a1,a2]
我希望程式現在能夠同時決議“as”和“Bs”,但是對于第二個字串,我得到一個錯誤“期望空格或小寫字母”。好的,我認為無論采用哪個選項都會決議空格,但顯然不是這樣,讓我們spaces在第二個選項的開頭放另一個,如下所示:
testP :: Parser String
testP = do
spaces
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
spaces
a1 <- upper
a2 <- lower
return [a1,a2]
但是,當我嘗試決議“ Bs”時,這仍然給我同樣的錯誤。我是如何誤解這里的空白處理的,我怎么能正確地做到這一點?
uj5u.com熱心網友回復:
<|>如果第一個決議器消耗了任何東西,則不會嘗試第二個選擇。這樣做是為了防止空間泄漏。這是 parsec 的基本設計之一。
當spaces消耗一些輸入時,一切都決定了,決議器現在必須成功——否則,將不會嘗試替代方案,整個機器就會失敗。這就是您觀察這種行為的原因。spaces消耗一些輸入,lookAhead lower失敗,整個決議器失敗。
即使第一個消耗輸入,您也可以實作任意前瞻try并確保嘗試第二個替代方案,但您不應該這樣做,在這種情況下不是。這里spaces是一個非致命的決議器,它是這兩個操作的初步- 所以只需在你的任何一個選擇之前使用決議器。
testP :: Parser String
testP = spaces *> (do
lookAhead lower
a1 <- lower
a2 <- lower
return [a1,a2]
<|> do
a1 <- upper
a2 <- lower
return [a1,a2])
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/351369.html
