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
し、明らかな「リフト」メソッドも存在しません。
ベストアンサー1
通常のエンコードでは、列挙子は基本的に です。この型を特定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