1. ホーム
  2. scala

[解決済み] スカラズのイテレート。「より大きな」モナドのために `EnumeratorT` を `IterateeT` にマッチングさせる「リフティング」。

2022-03-21 15:33:12

質問

もし 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 を使用して、イテレートにマッチするように "lift" します。

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]

しかし、iterateeモナドがenumeratorモナドより"big"な場合はどうすればいいのでしょう?

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

このアプローチにより、必要な効果に特化した列挙体を定義することができますが、よりリッチなコンテキストを必要とする消費者と連携するために "lifting"を行うことができます。この例を修正して 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) }

これで、次のように合成することができます。

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

EnumeratorP はモナドである(もし F はアプリケーティブ)、そして EnumeratorP のような列挙子を定義するのに役立つ関数が用意されています。 EnumeratorT -があります。 empty , perform , enumPStream など。が必要なのでしょう。 EnumeratorT を使用して実装することができないインスタンスです。 EnumeratorP のエンコーディングがありますが、私の頭ではどのようなものかはわかりません。