2012-12-28 57 views
2

我想爲尖括號中逗號分隔的一對值編寫解析器。我把它用下面的方法工作:適用於具有兩個參數的構造函數的樣式解析器

pair p1 p2 = do 
    x1 <- p1 
    comma 
    x2 <- p2 
    return (x1, x2) 

data Foo = Foo (Bar, Bar) 

foo :: Parser Foo 
foo = Foo <$> (angles $ pair bar bar) 

但是我寧願富構造函數取兩個參數,而不是一個元組:

data Foo = Foo Bar Bar 

什麼是寫一個這樣的解析器的最佳方法?理想情況下,我想重複使用標準的Parsec解析器,例如angles,並儘可能使用應用程序。

回答

8

寫這樣一個解析器的最好方法是什麼?理想情況下,我想重複使用標準的Parsec解析器,並儘可能使用應用程序。

在應用性的風格,你的解析器會

foo = angles $ Foo <$> bar <* comma <*> bar 

往裏走了,一個bar進行解析,然後comma,其被丟棄,另一bar,然後構造Foo被應用到兩個解析bar s。最後,所有被裹入angles組合子,以便在窗體

< bar , bar > 

的字符串被解析(bar應該可能消耗尾隨空格)。

結合解析器忽略一個與*><*應用性組合子的結果消除了pair組合子的必要性,並容易推廣到考慮的參數任意數量的構造。

正如在評論中提到C.A. McCann,該(<$)組合子(這是GHC的實現Functor類的一部分,默認實現(<$) = fmap . const;但它不是語言標準的一部分)是太有用,如果你想忽略領先的令牌。利用這一點,你可以寫

Foo <$ ignoreMe <*> bar <* comma <*> baz 

這比使用括號

Foo <$> (ignoreMe *> bar) <* comma <*> baz 

pure更好,

pure Foo <* ignoreMe <*> bar <* comma <*> baz 

如會以某種形式要求沒有它。

+2

此外,對於您有領先令牌忽略的情況,您可以使用類似'Foo <$ keywordFoo <*> bar <* comma <*> baz'。不過,我忘記了定義了哪個'(<$)'並將其導出。 –

+1

''class Functor f where ...(<$) :: a -> f b - > f a - 定義在'GHC.Base'infixl 4 <$''好點,這也很有用。 –

相關問題