2016-11-16 99 views
0

這樣做的目的是使用StateT充當分析器實施(<++)內一個Haskell解析器

import Control.Monad.State 

    type Parser = StateT String [] 

    runParser :: Parser a -> String -> [(a,String)] 
    runParser = runStateT 

    parser :: (String -> [(a,String)]) -> Parser a 
    parser = StateT 

    (<++) :: Parser a -> Parser a -> Parser a 

從這個基礎上,我怎樣可以實現<實施< ++在Haskell ++因此它反映了Text.ParserCombinators.ReadP

本地排他性左偏向選擇:如果左側解析器本地產生任何結果,則不使用右側解析器。

+0

不知道如何解決這個問題。我不知道如何對第一個解析器應用優先級,以便如果成功,程序不會去檢查第二個解析器。然後失敗後,代碼檢查第二個解析器。如果我只是想將兩個解析器結合使用,我可以使用mplus或msum,但是我不確定如何將其減少到僅返回1的值。我不知道如何解決這個問題。 – Kayanda

+1

從思考一個失敗的解析鬆開開始。 – mnoronha

+0

一個空列表是正確的,但問題是,如果兩個解析器都成功並被組合,我會得到兩個結果。在這種情況下,我只希望第一個解析器成功。如果第一個或第二個失敗,則(<++)等同於'mplus'。如果兩者都成功,那麼它們就不再是等價的。我應該如何處理這種情況 – Kayanda

回答

3

您的解析器是函數String -> [(a,String)]其中參數是初始狀態。因此,讓構建試圖第一解析器這樣的功能,如果失敗,將嘗試第二解析器:

(<++) :: Parser a -> Parser a -> Parser a 
p1 <++ p2 = 
    parser $ \s0 ->   -- 1. captures initial state 
    case runParser p1 s0 of -- 2. run first parser 
     (x:xs) -> x : xs  -- 3. success 
     [] -> runParser p2 s0 -- 4. otherwise run second parser 

有些解析器預期嘗試了這一點

-- | Always fails 
failP :: Parser a 
failP = parser (const []) 

-- | Parses an Int 
intP :: Parser Int 
intP = parser reads 

輸出? (也許還有更多啓發性的測試案例...)

λ> runParser (failP <++ intP) "2014" 
[(2014,"")] 
λ> runParser (intP <++ failP) "2014" 
[(2014,"")] 
λ> runParser (intP <++ intP) "2014" 
[(2014,"")] 
+0

謝謝,我嘗試了類似的方法,但忘記將lambda函數包裝在解析器中,因此類型檢查失敗。這現在總是有意義的。 – Kayanda

+0

@Kayanda在Stackoverflow上習慣性地使用分數旁邊的複選標記來標記答案,如果答案足夠。 – adamse