webentwicklung-frage-antwort-db.com.de

Scalaz iteriert: "Lifting" `EnumeratorT` passend zu` IterateeT` für eine "größere" Monade

Wenn ich ein EnumeratorT und ein entsprechendes IterateeT habe, kann ich sie zusammen ausführen:

val en: EnumeratorT[String, Task] = EnumeratorT.enumList(List("a", "b", "c"))
val it: IterateeT[String, Task, Int] = IterateeT.length

(it &= en).run : Task[Int]

Wenn die Enumerator-Monade "größer" als die Iteratee-Monade ist, kann ich up oder allgemeiner Hoist verwenden, um den Iteratee entsprechend zu "heben":

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]

Aber was mache ich, wenn die iterierte Monade "größer" ist als die Enumerator-Monade?

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

it &= ???

Es scheint weder eine Hoist -Instanz für EnumeratorT noch eine offensichtliche "Lift" -Methode zu geben.

444
lmm

In der üblichen Codierung ist ein Enumerator im Wesentlichen ein StepT[E, F, ?] ~> F[StepT[E, F, ?]]. Wenn Sie versuchen, eine generische Methode zu schreiben, die diesen Typ in einen Step[E, G, ?] ~> G[Step[E, G, ?]] mit einem F ~> G konvertiert, tritt schnell ein Problem auf: Sie müssen einen Step[E, G, A] auf einen Step[E, F, A] "senken", um den ursprünglichen Enumerator anwenden zu können.

Scalaz bietet auch eine alternative Enumerator-Codierung , die so aussieht:

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

Dieser Ansatz ermöglicht es uns, einen Enumerator zu definieren, der spezifisch für die benötigten Effekte ist, der jedoch "aufgehoben" werden kann, um mit Verbrauchern zu arbeiten, die umfangreichere Kontexte benötigen. Wir können Ihr Beispiel so ändern, dass es EnumeratorP verwendet (und den neueren Ansatz der natürlichen Transformation anstelle der alten Teilreihenfolge der Monaden):

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

Wir können die beiden nun so zusammensetzen:

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

EnumeratorP ist monadisch (wenn F anwendbar ist), und das Begleitobjekt EnumeratorP bietet einige Funktionen zur Definition von Enumeratoren, die denen in EnumeratorT - Es gibt empty, perform, enumPStream usw. Ich denke, es muss EnumeratorT Instanzen geben, die mit EnumeratorP Codierung, aber auf den ersten Blick bin ich mir nicht sicher, wie sie aussehen würden.

4
Travis Brown