2013-02-03 44 views
4
import Data.Attoparsec.Text.Lazy 
import Data.Text.Lazy.Internal (Text) 
import Data.Text.Lazy (pack) 

data List a = Nil | Cons a (List a) 

list :: Text 
list = pack $ unlines 
    [ "0" 
    , "1" 
    , "2" 
    , "5" 
    ] 

遞歸數據如何List Int解析器coud實現解析從listCons 0 (Cons 1 (Cons 2 (Cons 5 Nil)))解析用秒差距

ps:純解析器不解析[Int]並將其轉換爲List Int是優選的。

回答

6

像這樣:

import Control.Applicative 
-- rest of imports as in question 

data List a = Nil | Cons a (List a) 
    deriving Show -- for testing 

-- definition of list as in question 

parseList :: Parser (List Int) 
parseList = foldr Cons Nil <$> many (decimal <* endOfLine) 

測試中GHCI:

*Main> parse parseList list 
Done "" Cons 0 (Cons 1 (Cons 2 (Cons 5 Nil))) 
1

我會說,我們可以通過檢查many'做到這一點:

many' :: (MonadPlus m) => m a -> m [a] 
many' p = many_p 
    where 
    many_p = some_p `mplus` return [] 
    some_p = liftM2' (:) p many_p 

我們可以讓我們自己變同樣地:

many'' :: (MonadPlus m) => m a -> m (List a) 
many'' p = many_p 
    where 
    many_p = some_p `mplus` return Nil 
    some_p = liftM2 Cons p many_p 

並將其應用於任何monadic分析器。

(請注意,many'使用自己liftM2'那就是在第一次行動的結果嚴格的。這不是模塊導出,所以我用一個普通的liftM2

或者,我們可以做出更一般的變體使用Alternative

many'' :: (Alternative f) => f a -> f (List a) 
many'' p = many_p 
    where 
    many_p = some_p <|> pure Nil 
    some_p = Cons <$> p <*> many_p 
2

沒有從INTS的列表將其轉換:

import Data.Attoparsec.Text.Lazy 
import Data.Text.Lazy (Text, pack) 
import Control.Applicative 

data List a = Nil | Cons a (List a) 
    deriving Show 

input :: Text 
input = pack $ unlines [ "0", "1", "2", "5"] 

list :: Parser (List Int) 
list = cons <|> nil 
    where 
    cons = Cons <$> (decimal <* endOfLine) <*> list 
    nil = pure Nil 

main = print $ parse list input 

正如你所看到的,列表解析器幾乎看起來像它解析的數據類型。

+0

這是可編譯的,甚至typecheckable? –

+0

哎呀,對不起。我將解析器重命名爲與kosmikus答案中的名稱相同,但忘記了在where子句中這樣做。編輯爲可編輯。 – bzn

+0

按照要求,這實際上是一個遞歸解析器。 – jekor

1

正如其他人指出的,你實際上不需要使用遞歸(儘管你可以)來解析列表。但是如果你有一個遞歸語法來解析,你可以在解析器中使用遞歸(請參閱bzn的答案和Petr的答案),或者可以解析解析器的結果(例如在Markdown中看到的嵌套)。後者我在這裏覆蓋:http://www.youtube.com/watch?v=nCwG9ijQMuQ&t=17m32s