Se eu tiver um EnumeratorT
e um correspondente IterateeT
, posso executá-los juntos:
val en: EnumeratorT[String, Task] = EnumeratorT.enumList(List("a", "b", "c"))
val it: IterateeT[String, Task, Int] = IterateeT.length
(it &= en).run : Task[Int]
Se a mônada do enumerador for "maior" que a mônada do iterado, eu posso usar up
ou, de maneira mais geral, Hoist
"elevar" o iterado para corresponder:
val en: EnumeratorT[String, Task] = ...
val it: IterateeT[String, Id, Int] = ...
val liftedIt = IterateeT.IterateeTMonadTrans[String].hoist(
implicitly[Task |>=| Id]).apply(it)
(liftedIt &= en).run: Task[Int]
Mas o que faço quando a mônada iterada é "maior" que a mônada do enumerador?
val en: EnumeratorT[String, Id] = ...
val it: IterateeT[String, Task, Int] = ...
it &= ???
Parece não haver um Hoist
exemplo EnumeratorT
nem método óbvio de "levantamento".
Enumerator
é realmente apenas um invólucro em torno de umStepT => IterateeT
, o que sugere que você precisará "renunciar" de umStepT[E, BigMonad, A]
.Enumerator
é apenas uma fonte eficaz, certo? Parece que eu deveria poder usar algo que possa fornecerA
para suprirTask[A]
.Respostas:
Na codificação usual, um enumerador é essencialmente a
StepT[E, F, ?] ~> F[StepT[E, F, ?]]
. Se você tentar escrever um método genérico que converta esse tipo em umStep[E, G, ?] ~> G[Step[E, G, ?]]
dadoF ~> G
, você encontrará rapidamente um problema: é necessário "diminuir" de aStep[E, G, A]
para aStep[E, F, A]
para poder aplicar o enumerador original.O Scalaz também fornece uma codificação de enumerador alternativa que se parece com isso:
Essa abordagem nos permite definir um enumerador específico sobre os efeitos de que precisa, mas que pode ser "levantado" para trabalhar com consumidores que exigem contextos mais ricos. Podemos modificar seu exemplo para usar
EnumeratorP
(e a abordagem mais recente de transformação natural, em vez da antiga ordem parcial da mônada):Agora podemos compor os dois assim:
EnumeratorP
é monádico (se oF
é aplicativo) e oEnumeratorP
objeto companheiro fornece algumas funções para ajudar com a definição de recenseadores que se parecem muito com os que estão naEnumeratorT
-Não háempty
,perform
,enumPStream
, etc. Eu acho que tem que haverEnumeratorT
instâncias que não poderiam ser implementadas usando aEnumeratorP
codificação, mas no topo da minha cabeça não tenho certeza de como eles seriam.fonte