Scalaz イテレータ: `EnumeratorT` を `IterateeT` に合わせて「持ち上げて」、より大きなモナドにする 質問する

Scalaz イテレータ: `EnumeratorT` を `IterateeT` に合わせて「持ち上げて」、より大きなモナドにする 質問する

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 ~> GStep[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コンパニオン オブジェクトは の列挙子によく似た列挙子の定義を支援するいくつかの関数を提供しますEnumeratorTemptyperform、などがあります。 エンコーディングを使用して実装できないインスタンスもenumPStreamあるはずですが、すぐにはどのようなものになるかわかりません。EnumeratorTEnumeratorP

おすすめ記事