EnumeratorT
と対応するIterateeT
がある場合、それらを一緒に実行できます。
val en: EnumeratorT[String, Task] = EnumeratorT.enumList(List("a", "b", "c"))
val it: IterateeT[String, Task, Int] = IterateeT.length
(it &= en).run : Task[Int]
列挙子モナドが反復子モナドよりも「大きい」場合、up
、またはより一般的にはHoist
を使用して、一致するように反復子を「持ち上げる」ことができます。
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]
しかし、反復子モナドが列挙子モナドより「大きい」場合はどうすればよいですか?
val en: EnumeratorT[String, Id] = ...
val it: IterateeT[String, Task, Int] = ...
it &= ???
Hoist
のEnumeratorT
インスタンスも、明らかな「リフト」メソッドも存在しないようです。
通常のエンコードでは、列挙子は本質的にStepT[E, F, ?] ~> F[StepT[E, F, ?]]
です。このタイプをStep[E, G, ?] ~> G[Step[E, G, ?]]
に変換してこのタイプをF ~> G
に変換する汎用メソッドを作成しようとすると、すぐに問題が発生します。元の列挙子を適用するには、Step[E, G, A]
をStep[E, F, A]
に「下げる」必要があります。
Scalazは、次のような 代替列挙子エンコーディング も提供します。
trait EnumeratorP[E, F[_]] {
def apply[G[_]: Monad](f: F ~> G): EnumeratorT[E, G]
}
このアプローチにより、必要な効果に固有の列挙子を定義できますが、より豊かなコンテキストを必要とする消費者と連携するために「持ち上げる」ことができます。 EnumeratorP
(および古いモナド半順序ではなく、より新しい自然な変換アプローチ)を使用するように例を変更できます。
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) }
次のように2つを構成できます。
scala> def result = (iter &= enum(toTask)).run
result: scalaz.concurrent.Task[Int]
EnumeratorP
はモナドです(F
が適用可能な場合)、EnumeratorP
コンパニオンオブジェクトは、EnumeratorT
によく似た列挙子の定義を支援する関数を提供します。 empty
、perform
、enumPStream
などがあります。EnumeratorT
エンコードを使用して実装できなかったEnumeratorP
インスタンスが存在する必要があると思いますが、オフ私の頭の上では、彼らがどのように見えるかわかりません。