2011-11-08 93 views
10

許多秒差距組合子我使用的是一種類型的,例如:標的秒差距單子

foo :: CharParser st Foo 

CharParser定義here爲:

type CharParser st = GenParser Char st 

CharParser因此涉及GenParser類型同義詞,本身定義爲here爲:

type GenParser tok st = Parsec [tok] st 

GenParser然後另一種類型的同義詞,使用Parsec分配,定義here爲:用的話沿着

data ParsecT s u m a 

type Parsec s u = ParsecT s u Identity 

所以Parsec是的局部應用,本身帶有類型列出here

「ParsecT suma是一個解析器與ST令牌類型s,用戶狀態類型u, 基本monad m和返回類型a「。

什麼是底層monad?特別是,當我使用CharParser解析器時,它是什麼?我看不到它被插入堆棧中的位置。與Monadic Parsing in Haskell中的列表monad的使用是否有關係,以從模糊解析器返回多個成功的分析?

回答

6

GenParser是根據Parsec而不是ParsecT定義的。 Parsec又被定義爲

type Parsec s u = ParsecT s u Identity 

所以答案是,當使用CharParser時,底層monad是身份monad。

+1

謝謝,我編輯了我的問題,包括該步驟。所以它是monad變壓器的基礎。我認爲這與Hutton/Meijer論文中描述的模糊解析沒有關係。那麼列表monad的使用是否出現在Parsec分析器的任何地方? Parsec只是非含糊嗎?如果是這樣,是用'Maybe'還是'Either'編碼的? – user2023370

+1

底層monad不被parsec自身使用,因此不會影響歧義。 – augustss

+0

我想我想問的是Hutton/Meijer論文中單子monad之間的關係;和[消費](http://hackage.haskell.org/packages/archive/parsec/latest/doc/html/Text-Parsec-Prim.html#t:Consumed)和[回覆](http:// hackage .haskell.org/packages/archive/parsec/latest/doc/html/Text-Parsec-Prim.html#t:Reply)類型。 – user2023370

7

在你的情況下,基礎monad是Identity。然而,ParsecT與大多數單子變換器的不同之處在於它是Monad類的實例,即使類型參數m不是。如果您查看源代碼,您會注意到實例聲明中缺少「(Monad m) =>」。所以你問自己:「如果我有一個不平凡的monad堆棧,它將在哪裏使用?」

這裏有三個答案對這個問題的:

  1. 它是用來uncons下一個標記出流:

    class (Monad m) => Stream s m t | s -> t where 
        uncons :: s -> m (Maybe (t,s)) 
    

    注意uncons需要一個s(流的令牌t)並返回其包裹在monad中的結果。這使得人們可以在獲取下一個標記的過程中或甚至在獲取下一個標記的過程中做有趣的事情

  2. 它用在每個解析器的結果輸出中。這意味着您可以創建不接觸輸入的解析器,但可以在底層monad中執行操作,並使用組合器將它們綁定到常規解析器。換句話說,lift (x :: m a) :: ParsecT s u m a

  3. 最後,RunParsecT和朋友的最終結果(直到你建立到m被替換爲Identity的點)返回包裹在這個monad中的結果。

這個monad和Monadic Parsing in Haskell之間沒有關係。在這種情況下,Hutton和Meijer指的是ParsecT本身的monad實例。事實上,在Parsec-3.0.0及以後的版本中,ParsecT已經成爲一個帶有基礎monad的monad變壓器,與該論文無關。

但是我認爲你正在尋找的是可能的結果列表。在Hutton和Meijer中,解析器返回所有可能結果的列表,而Parsec固執地只返回一個結果。我認爲你正在看結果中的m,並且自己想,結果列表必須隱藏在某處。不是這樣。

由於效率原因,Parsec選擇了更喜歡Hutton和Meijer結果列表中的第一個匹配結果。這讓我們可以拋棄Hutton和Meijer列表尾部的未使用結果,也可以拋棄令牌流的前端,因爲我們永遠不會回溯。在parsec中,給定組合語法分析器a <|> b,如果a消耗任何輸入b將永遠不會被評估。解決方法是try,如果a失敗,然後評估b,將會將狀態重置回原來的位置。

您在評論中詢問這是否使用MaybeEither完成。答案是「幾乎但不完全」。如果您查看低功能run*功能,您會看到它們返回一個代數類型,它告訴天氣輸入已被消耗,然後第二個返回結果或錯誤消息。這些類型的工作類似於Either,但即使它們不是直接使用。相反,然後進一步擴展,我會告訴你由Antoine Latter the post,解釋這是如何工作的,爲什麼這樣做。