2013-01-11 61 views
13

我對attoparsec的這種行爲有點困惑。當我期望看到失敗時,爲什麼我會用attoparsec看到部分結果?

$ ghci 
> :m Data.Attoparsec.Text 
> :m + Data.Text 
> parse (string (pack "module")) (pack "mox") 
Partial _ 
> parse (string (pack "module")) (pack "moxxxx") 
Fail "moxxxx" [] "Failed reading: takeWith" 
> 

爲什麼我需要添加字符來觸發失敗?

只要遇到第一個「x」,它不應該失敗嗎?

+0

爲了將來的參考,我打開了一張票,Attoparsec維護人員修復了這個錯誤:https://github.com/bos/attoparsec/issues/97 –

回答

13

這是一個實現細節,string解析器在知道是否有足夠的輸入可能會成功之前未完成。這是這些解析器的全有或全無行爲的結果(我認爲這對於性能通常很好)。

string :: Text -> Parser Text 
string s = takeWith (T.length s) (==s) 

string s試圖採取length s單位Text,然後將它們與s比較。

takeWith :: Int -> (Text -> Bool) -> Parser Text 
takeWith n p = do 
    s <- ensure n 
    let h = unsafeTake n s 
     t = unsafeDrop n s 
    if p h 
    then put t >> return h 
    else fail "takeWith" 

takeWith n p首先嚐試確保n單位Text可用,

ensure :: Int -> Parser Text 
ensure !n = T.Parser $ \i0 a0 m0 kf ks -> 
    if lengthAtLeast (unI i0) n 
    then ks i0 a0 m0 (unI i0) 
    else runParser (demandInput >> go n) i0 a0 m0 kf ks 
    where 
    go n' = T.Parser $ \i0 a0 m0 kf ks -> 
     if lengthAtLeast (unI i0) n' 
     then ks i0 a0 m0 (unI i0) 
     else runParser (demandInput >> go n') i0 a0 m0 kf ks 

ensure n創建一個延續,要求更多的稀粥輸入(Partial結果),如果沒有找到足夠的輸入立即。

你可以得到一個失敗與

Prelude Data.Attoparsec.Text Data.Text> parseOnly (string (pack "module")) (pack "mox") 
Left "not enough input" 

告訴解析器前面,它不會得到任何更多的輸入(然後從ensuredemandInput使它失效),或更高版本

Prelude Data.Attoparsec.Text Data.Text> parse (string (pack "module")) (pack "mox") 
Partial _ 
Prelude Data.Attoparsec.Text Data.Text> feed it (pack "") 
Fail "mox" ["demandInput"] "not enough input" 

通過告訴Partial結果表明那是它,給它一個空的Text

+0

謝謝 - 在您的解釋之後,這是有意義的。 – timbod

相關問題