Scalaz iteratees: "Lifting" `EnumeratorT` per abbinare` IterateeT` per una monade “più grande”


445

Se ho un EnumeratorTe un corrispondente IterateeTposso eseguirli insieme:

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 la monade dell'enumeratore è "più grande" della monade iterata, posso usare upo, più in generale, Hoistper "sollevare" l'iterata affinché corrisponda:

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]

Ma cosa devo fare quando la monade iterata è "più grande" della monade enumeratrice?

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

it &= ???

Non sembra esserci Hoistun'istanza EnumeratorTné un metodo evidente di "sollevamento".


59
+1 per una domanda chiara, ma all'inizio non sono sicuro della mia testa che questo è possibile nel caso generale, poiché un Enumeratorè davvero solo un involucro attorno a un StepT => IterateeT, il che suggerisce che dovrai "dimettermi" da a StepT[E, BigMonad, A].
Travis Brown,

12
Sì, l'ho scoperto quando ho cercato di implementarlo direttamente. Ma logicamente Enumeratorè solo una fonte efficace, giusto? Mi sento come se dovessi essere in grado di utilizzare qualcosa che può fornire Aper fornire Task[A].
mm

8
Non so abbastanza su Scala per offrire una risposta, ma non potresti definire il tuo tipo e fornire un meccanismo di sollevamento per esso ?
Rob,

8
No, non è affatto la stessa cosa, è un diverso tipo di "sollevamento".
mmm

2
@TravisBrown in questo momento c'è una taglia su questo, se vuoi scriverlo.
Aaron Hall

Risposte:


4

Nella solita codifica un enumeratore è essenzialmente un StepT[E, F, ?] ~> F[StepT[E, F, ?]]. Se provi a scrivere un metodo generico convertendo questo tipo in un Step[E, G, ?] ~> G[Step[E, G, ?]]dato an F ~> G, ti imbatterai rapidamente in un problema: devi "abbassare" Step[E, G, A]a Step[E, F, A]a per poter applicare l'enumeratore originale.

Scalaz fornisce anche una codifica enumeratrice alternativa simile alla seguente:

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

Questo approccio ci consente di definire un enumeratore specifico per gli effetti di cui ha bisogno, ma che può essere "sollevato" per lavorare con i consumatori che richiedono contesti più ricchi. Possiamo modificare il tuo esempio da usare EnumeratorP(e il più recente approccio di trasformazione naturale anziché il vecchio ordine parziale della monade):

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

Ora possiamo comporre i due in questo modo:

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

EnumeratorPè monadica (se l' Fè applicativo), e l' EnumeratorPoggetto associato fornisce alcune funzioni per aiutare con la definizione di enumeratori che sembrano un po 'come quelli sul EnumeratorTdi -Ci empty, perform, enumPStream, ecc ho lì immagino devono essere EnumeratorTistanze che non potrebbero essere attuate mediante la EnumeratorPcodifica, ma dalla parte superiore della mia testa non sono sicuro di come sarebbero.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.