Scalaz iteratees: "Lifting" `EnumeratorT` เพื่อให้ตรงกับ IterateeT สำหรับ monad ที่ใหญ่กว่า


445

หากฉันมี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 monad ฉันสามารถใช้upหรือโดยทั่วไปHoistเพื่อ "ยก" iteratee เพื่อให้ตรงกับ:

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หรือวิธีการ "ยก" ที่ชัดเจนใด ๆ


59
+1 สำหรับคำถามที่เรียบร้อย แต่จากข้างบนฉันไม่แน่ใจในหัวของฉันว่านี่เป็นไปได้ในกรณีทั่วไปเนื่องจาก a Enumeratorเป็นเพียง wrapper รอบ a StepT => IterateeTซึ่งแนะนำว่าคุณจะต้อง "ก้าวลง" StepT[E, BigMonad, A]จาก
Travis Brown

12
ใช่ฉันพบว่าเมื่อฉันพยายามนำไปใช้โดยตรง แต่เหตุผลEnumeratorก็เป็นเพียงแหล่งที่มีประสิทธิภาพใช่มั้ย รู้สึกว่าฉันควรจะใช้สิ่งที่สามารถAจัดหาTask[A]ได้
lmm

8
ฉันไม่รู้พอเกี่ยวกับ Scala ที่จะให้คำตอบ แต่คุณไม่สามารถกำหนดประเภทของคุณเองและให้กลไกการยกมันได้หรือไม่
Rob

8
ไม่นั่นไม่ใช่สิ่งเดียวกันเลยมันเป็น "การยก" ที่แตกต่างออกไป
lmm

2
@ TravisBrown มีความโปรดปรานในเรื่องนี้ในตอนนี้ถ้าคุณต้องการที่จะเขียนมันขึ้นมา
Aaron Hall

คำตอบ:


4

StepT[E, F, ?] ~> F[StepT[E, F, ?]]ในการเข้ารหัสปกติแจงนับเป็นหลัก หากคุณพยายามที่จะเขียนวิธีการทั่วไปที่แปลงชนิดนี้เป็นแบบที่Step[E, G, ?] ~> G[Step[E, G, ?]]ระบุF ~> Gคุณจะพบปัญหาอย่างรวดเร็ว: คุณต้อง "ลด" a Step[E, G, A]ไปเป็น a Step[E, F, A]เพื่อที่จะสามารถใช้ตัวแจงนับต้นฉบับได้

Scalaz ยังให้การเข้ารหัสตัวแจงนับทางเลือกที่มีลักษณะดังนี้:

trait EnumeratorP[E, F[_]] {
  def apply[G[_]: Monad](f: F ~> G): EnumeratorT[E, G]
}

วิธีนี้ช่วยให้เราสามารถกำหนดตัวแจงนับที่เฉพาะเจาะจงเกี่ยวกับผลกระทบที่ต้องการ แต่สามารถ "ยกระดับ" เพื่อทำงานกับผู้บริโภคที่ต้องการบริบทที่สมบูรณ์ยิ่งขึ้น เราสามารถแก้ไขตัวอย่างของคุณเพื่อใช้EnumeratorP(และวิธีการแปลงตามธรรมชาติที่ใหม่กว่าแทนที่จะเป็นคำสั่งบางส่วนของ monad เก่า)

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เป็น applicative) และEnumeratorPวัตถุสหายให้ฟังก์ชั่นบางอย่างเพื่อให้ความช่วยเหลือเกี่ยวกับการกำหนด enumerators ที่ดูมากเช่นคนในEnumeratorTของ -there empty, perform, enumPStreamฯลฯ ผมคิดว่ามีจะต้องเป็นEnumeratorTกรณีที่ไม่สามารถดำเนินการโดยใช้ การEnumeratorPเข้ารหัส แต่อยู่ด้านบนของหัวของฉันฉันไม่แน่ใจว่าพวกเขาจะมีลักษณะอย่างไร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.