[scala] Scalaz는 “거대한”모나드에 대해 ItateeT와 일치하도록 “리프팅”`EnumeratorT`를 반복합니다.

내가 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]

열거 자 모나드가 iteratee 모나드보다 “더 큰”경우 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]

그러나 iteratee 모나드가 열거 자 모나드보다 “더 큰”경우 어떻게해야합니까?

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하면 문제가 발생합니다. 원래 열거자를 적용하려면 a 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) }

이제 다음과 같이 두 가지를 구성 할 수 있습니다.

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

EnumeratorP합니다 (이 경우 모나드이다 F실용적이다), 그리고 EnumeratorP동반자 개체에있는 것과 같은 많은 모양 열거 정의하는 데 도움이되는 몇 가지 기능을 제공 EnumeratorT저기의를 empty, perform, enumPStream, 등 내가 거기 추측해야 EnumeratorT사용하여 구현 할 수없는 경우 EnumeratorP인코딩,하지만 내 머리 위로 떨어져 나는 확실히 그들이 어떻게 보이는지 모르겠어요.


답변