scala monads scalaz enumerator iterate

Scalaz iteratees: ''Elevating'' ''EnumeratorT` para que coincida con'' IterateeT` para una mónada “más grande”



monads (1)

En la codificación habitual, un enumerador es esencialmente un StepT[E, F, ?] ~> F[StepT[E, F, ?]] . Si intenta escribir un método genérico que convierta este tipo en un Step[E, G, ?] ~> G[Step[E, G, ?]] Dado un F ~> G , rápidamente se encontrará con un problema: necesita "bajar" un Step[E, G, A] a un Step[E, F, A] para poder aplicar el enumerador original.

Scalaz también proporciona una codificación de enumerador alternativa que se ve así:

trait EnumeratorP[E, F[_]] { def apply[G[_]: Monad](f: F ~> G): EnumeratorT[E, G] }

Este enfoque nos permite definir un enumerador que sea específico sobre los efectos que necesita, pero que puede "levantarse" para trabajar con consumidores que requieren contextos más ricos. Podemos modificar su ejemplo para usar EnumeratorP (y el nuevo enfoque de transformación natural en lugar del antiguo orden parcial de mónada):

import scalaz._, Scalaz._, iteratee._, concurrent.Task def enum: EnumeratorP[String, Id] = ??? def iter: IterateeT[String, Task, Int] = ??? val toTask = new (Id ~> Task) { def apply[A](a: A): Task[A] = Task(a) }

Ahora podemos componer los dos así:

scala> def result = (iter &= enum(toTask)).run result: scalaz.concurrent.Task[Int]

EnumeratorP es monádico (si la F es aplicativa), y el objeto complementario EnumeratorP proporciona algunas funciones para ayudar a definir enumeradores que se parecen mucho a los de EnumeratorT : hay empty , perform , enumPStream , etc. Supongo que tiene que haber EnumeratorT instancias que no se pudieron implementar usando la codificación EnumeratorP , pero fuera de mi cabeza no estoy seguro de cómo se verían.

Si tengo un EnumeratorT y un IterateeT correspondiente, puedo ejecutarlos 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]

Si la mónada enumeradora es "más grande" que la mónada iterada, puedo usar o, más en general, Hoist para "levantar" la iteración para que coincida:

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]

Pero, ¿qué hago cuando la mónada iteratee es "más grande" que la mónada enumeradora?

val en: EnumeratorT[String, Id] = ... val it: IterateeT[String, Task, Int] = ... it &= ???

No parece haber una instancia de Hoist para EnumeratorT , ni ningún método obvio de "elevación".