Si j'ai un EnumeratorT
et un correspondant, IterateeT
je peux les exécuter ensemble:
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 monade énumératrice est "plus grosse" que la monade itérée, je peux utiliser up
ou, plus généralement, Hoist
"lever" l'itérée pour qu'elle corresponde:
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]
Mais que dois-je faire lorsque la monade itérative est "plus grosse" que la monade énumératrice?
val en: EnumeratorT[String, Id] = ...
val it: IterateeT[String, Task, Int] = ...
it &= ???
Il ne semble pas y avoir d' Hoist
exemple EnumeratorT
ni de méthode de "lift" évidente.
Enumerator
est vraiment juste un wrapper autour d'unStepT => IterateeT
, ce qui suggère que vous devrez "démissionner" d'unStepT[E, BigMonad, A]
.Enumerator
c'est juste une source efficace, non? J'ai l'impression que je devrais pouvoir utiliser une chose qui peut fournirA
à fournirTask[A]
.Réponses:
Dans le codage habituel, un énumérateur est essentiellement un
StepT[E, F, ?] ~> F[StepT[E, F, ?]]
. Si vous essayez d'écrire une méthode générique convertissant ce type en unStep[E, G, ?] ~> G[Step[E, G, ?]]
donnéF ~> G
, vous rencontrerez rapidement un problème: vous devez "abaisser" unStep[E, G, A]
à unStep[E, F, A]
afin de pouvoir appliquer l'énumérateur d'origine.Scalaz fournit également un encodage d'énumérateur alternatif qui ressemble à ceci:
Cette approche nous permet de définir un énumérateur qui est spécifique sur les effets dont il a besoin, mais qui peut être «levé» pour travailler avec des consommateurs qui nécessitent des contextes plus riches. Nous pouvons modifier votre exemple à utiliser
EnumeratorP
(et la nouvelle approche de transformation naturelle plutôt que l'ancien ordre partiel de la monade):Nous pouvons maintenant composer les deux comme ceci:
EnumeratorP
est monadique (si leF
est applicatif), et l'EnumeratorP
objet compagnon fournit des fonctions pour aider à définir les agents recenseurs qui ressemblent beaucoup à ceux surEnumeratorT
de -Ilempty
,perform
,enumPStream
, etc. Je pense qu'il faut être desEnumeratorT
cas qui ne pouvaient pas être mises en œuvre à l' aide l'EnumeratorP
encodage, mais du haut de ma tête, je ne sais pas à quoi ils ressembleraient.la source