2011-10-05 5 views
10

Sto cercando di comprendere la libreria enumerator e ho eseguito una situazione in cui desidero creare un nuovo enumerato in termini di due enumerati esistenti. Diciamo che ho le enumeratees:Combinazione di due enumerati

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

sento che dovrei essere in grado di combinare in uno enumeratee

e3 :: Enumeratee x z m b 

ma non riuscivo a trovare una funzione esistente per fare questo nel pacchetto. Ho provato a scrivere una funzione del genere da solo, ma la mia comprensione degli iterate è ancora così limitata che non riesco a trovare un modo per far combaciare tutti i tipi complessi.

Mi sono perso un po 'di combinatore di base, o gli Enumerati si suppone che siano componibili l'uno con l'altro?

risposta

3

In teoria sono componibili, ma i tipi sono un po 'complicati. La difficoltà è che il parametro finale b del primo enumerato non è in realtà b; è un'altra iterazione !. Ecco il tipo di ><> operatore dal iteratee, che compone 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 

nota l'extra forall nel primo enumeratee; questo indica che un tipo di Rank-2 è al lavoro. Se l'autore enumerator desidera mantenere la compatibilità H98 (credo che questo fosse uno degli obiettivi originali), questo approccio non è disponibile.

È possibile scrivere questo tipo di firma in un formato che non richiede i tipi di Rank-2, ma è più lungo, non chiaro dal tipo che si tratta in realtà di due enumerate o di entrambi. Ad esempio, questo è tipo derivato di GHC per (><>):

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

Anche se questi tipi sono per iteratee combinatori, si spera che sia abbastanza informazioni che sarete in grado di applicarle a enumerator.

1

Ho eseguito con questo problema qualche tempo fa, è necessario avere un Iteratee prima (o un Enumeratore) al fine di rendere la composizione di Enumeratees.

è possibile iniziare in questo modo:

 
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) 

Il codice precedente compone un elenco di enumeratees insieme per creare un nuovo enumeratore, e poi viene applicato al Iteratee consumare.

L'($ =) serve per comporre un enumeratore e un Enumeratee per creare un nuovo enumeratore, mentre il (= $) può essere utilizzato per comporre un Iteratee con un'Enumeratee per creare un nuovo Iteratee. Vi consiglio il secondo dato che i tipi non busto le palle durante la composizione di una lista di Enumeratees usando (= $):

 
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)) 
       ] 

Se volete cercare di attuare la stessa funzione di cui sopra con la creazione di un enumeratore invece di un Iteratee , si otterrà un errore di tipo ricorsivo infinito quando si utilizza foldl' ($=) (enumList 5 [1..]) [list-of-enumeratees].

Spero che questo aiuti.