2011-10-05 46 views
10

我試圖圍繞enumerator庫包裹我的頭,並遇到了一種情況,我想根據兩個現有的枚舉構建一個新的Enumeratee。比方說,我有enumeratees:合併兩個枚舉

e1 :: Enumeratee x y m b 
e2 :: Enumeratee y z m b 

我覺得我應該能夠將它們組合成一個enumeratee

e3 :: Enumeratee x z m b 

,但我無法找到一個現有的功能在包中做到這一點。我試圖自己編寫這樣一個函數,但是我對iteratees的理解仍然非常有限,以至於我無法找到讓所有複雜類型匹配的方法。

難道我只是想念一些基本的combinator,或者Enumeratees甚至應該是可以相互組合嗎?

回答

3

理論上它們是可組合的,但類型有點棘手。難點在於第一枚枚舉的最終參數b實際上並不是b;這是另一個迭代器!下面是從iteratee><>運營商,其組成enumeratees類型:

Prelude Data.Iteratee> :t (><>) 
(><>) 
    :: (Monad m, Nullable s1) => 
    (forall x. Enumeratee s1 s2 m x) 
    -> Enumeratee s2 s3 m a -> Enumeratee s1 s3 m a 

注意在第一enumeratee額外forall;這表明Rank-2類型正在工作。如果作者想保持H98的兼容性(我認爲這是最初的目標之一),這種方法是不可用的。

可以使用不需要Rank-2類型的形式來編寫此類簽名,但它可能更長,從類型中不清楚它實際上是正在編寫的兩個枚舉類型,或者兩者都有。例如,這是GHC對(><>)推斷類型:

Prelude Data.Iteratee> :t (><>>) 
(><>>) 
    :: (Monad m, Nullable s) => 
    (b -> Iteratee s m (Iteratee s' m a1)) 
    -> (a -> b) -> a -> Iteratee s m a1 

儘管這些類型是iteratee組合程序,希望這是足夠的信息,你就可以將它們應用到enumerator

1

前段時間我遇到了這個問題,你需要首先有一個Iteratee(或一個枚舉器)才能組成Enumeratees。

你可以通過這樣開始:

 
module Main where 
import Data.Enumerator 
import qualified Data.Enumerator.List as EL 

main :: IO() 
main = run_ (enum $$ EL.consume) >>= print 
    where 
    enum = (enumList 5 [1..] $= EL.isolate 100) $= EL.filter pairs 
    pairs = (==0) . (`mod` 2) 

上面的代碼組成enumeratees的列表,共同創建一個新的枚舉,然後將其應用到消費Iteratee。

的($ =)用於構成的枚舉和Enumeratee創建一個新的枚舉,而(= $)可被用於組成一個Iteratee與Enumeratee以創建新的Iteratee。我推薦後者因爲撰寫Enumeratees的使用(= $)的列表類型時不會破壞你的球:

 
module Main where 
import Data.Enumerator 
import qualified Data.Enumerator.List as EL 

main :: IO() 
main = run_ (enumList 5 [1..] $$ it) >>= print 
    where 
    it = foldr (=$) 
       EL.consume 
       [ EL.isolate 100 
       , EL.filter ((==0) . (`mod` 2)) 
       ] 

如果您想嘗試通過創建一個枚舉,而不是一個Iteratee,以實現上述同樣的功能當使用foldl' ($=) (enumList 5 [1..]) [list-of-enumeratees]時,您將獲得無限遞歸類型錯誤。

希望這會有所幫助。