2011-10-05 17 views
10

Estoy tratando de abarcar la biblioteca enumerator y me encontré con una situación en la que quiero construir un nuevo Enumeratee en términos de dos Enumeratees existentes. Vamos a decir que tengo los enumeratees:Combinando dos Enumeratees

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

siento que debería ser capaz de combinarlos en un solo enumeratee

e3 :: Enumeratee x z m b 

pero no pude encontrar una función existente para hacer esto en el paquete. Traté de escribir una función de este tipo, pero mi comprensión de iteratees es aún tan limitada que no pude encontrar la manera de hacer coincidir todos los tipos complejos.

¿Acabo de perderme un combinador básico, o se supone que los enumerados se pueden componer entre sí?

Respuesta

3

En teoría son composable, pero los tipos son un poco difíciles. La dificultad es que el parámetro final b del primer enumerado no es realmente b; es otro iteratee !. Aquí está el tipo de operador de ><>iteratee, que 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 extra forall en el primer enumeratee; esto indica que un tipo de Rango 2 está en el trabajo. Si el autor enumerator quiere mantener la compatibilidad H98 (creo que este fue uno de los objetivos originales), este enfoque no está disponible.

Es posible escribir este tipo de firma en un formulario que no requiere tipos de Rango 2, pero es más largo, no está claro del tipo en que se componen realmente dos enumerados, o ambos. Por ejemplo, este es el tipo inferido de GHC para (><>):

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

Aunque estos tipos son para iteratee combinadores, es de esperar que sea suficiente información que será capaz de aplicarlos a enumerator.

1

Me encontré con este problema hace un tiempo, necesita tener un Iteratee primero (o un Enumerator) para poder hacer la composición de Enumeratees.

Puede empezar por hacer esto:

 
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) 

El código anterior compone una lista de enumeratees juntos para crear un nuevo encuestador, y luego se aplica a la Iteratee consumir.

El ($ =) sirve para componer un Enumerador y un Enumeratee para crear un nuevo empadronador, mientras que el (= $) se puede utilizar para componer un Iteratee con un Enumeratee para crear un nuevo Iteratee. Recomiendo este último teniendo en cuenta que los tipos no van a reventar las pelotas al componer una lista de 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)) 
       ] 

Si desea tratar de poner en práctica la misma función anterior mediante la creación de un enumerador en lugar de un Iteratee , obtendrá un error de tipo recursivo infinito al usar foldl' ($=) (enumList 5 [1..]) [list-of-enumeratees].

Espero que esto ayude.