Scalaz iteriert: "Heben" von "EnumeratorT", um "IterateeT" für eine "größere" Monade zu finden

445

Wenn ich ein EnumeratorTund ein entsprechendes IterateeThabe, 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 die Iteratee verwenden upoder allgemeiner Hoist"anheben", um sie anzupassen:

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 HoistInstanz EnumeratorTnoch eine offensichtliche "Lift" -Methode zu geben.

lmm
quelle
59
+1 für eine nette Frage, aber von oben bin ich mir nicht sicher, ob dies im allgemeinen Fall möglich ist, da a Enumeratorwirklich nur ein Wrapper um a ist StepT => IterateeT, was darauf hindeutet, dass Sie "zurücktreten" müssen. von a StepT[E, BigMonad, A].
Travis Brown
12
Ja, das habe ich festgestellt, als ich versucht habe, es direkt zu implementieren. Aber logischerweise ist eine Enumeratornur eine wirksame Quelle, oder? Es fühlt sich so an, als ob ich in der Lage sein sollte, etwas zu verwenden, das liefern kann, um Azu liefern Task[A].
lmm
8
Ich weiß nicht genug über Scala, um eine Antwort zu geben, aber konnten Sie nicht Ihren eigenen Typ definieren und einen Hebemechanismus dafür bereitstellen ?
Rob
8
Nein, das ist überhaupt nicht dasselbe, es ist eine andere Art des "Hebens".
lmm
2
@TravisBrown Es gibt momentan ein Kopfgeld für dieses, wenn Sie es aufschreiben möchten.
Aaron Hall

Antworten:

4

In der üblichen Codierung ist ein Enumerator im Wesentlichen a StepT[E, F, ?] ~> F[StepT[E, F, ?]]. Wenn Sie versuchen , eine generische Methode Umwandlung dieser Art in einen schreiben Step[E, G, ?] ~> G[Step[E, G, ?]]gegeben ein F ~> G, werden Sie schnell in ein Problem laufen: Sie müssen „senken“ ein , Step[E, G, A]um eine Step[E, F, A]um in der Lage zu sein , den ursprünglichen enumerator anzuwenden.

Scalaz bietet auch eine alternative Enumerator-Codierung , die folgendermaßen 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 ändern, um es zu verwenden EnumeratorP(und den neueren natürlichen Transformationsansatz anstelle der alten Monaden-Teilreihenfolge):

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]

EnumeratorPmonadischen ist (wenn die Fapplicative ist) und das EnumeratorPBegleitobjekt bietet mit der Definition Enumeratoren einige Funktionen helfen, die viel wie die , die auf aussehen EnumeratorT-e ist empty, perform, enumPStreametc. Ich denke , es muss sein EnumeratorTInstanz , die nicht umgesetzt werden könnte unter Verwendung von die EnumeratorPKodierung, aber auf den ersten Blick bin ich mir nicht sicher, wie sie aussehen würden.

Travis Brown
quelle