All Downloads are FREE. Search and download functionalities are using the official Maven repository.

libretto.examples.santa.solution2.SantaClaus.scala Maven / Gradle / Ivy

The newest version!
package libretto.examples.santa.solution2

import libretto.scaletto.StarterApp
import libretto.scaletto.StarterKit.*
import libretto.stream.scaletto.DefaultStreams.Source
import scala.{:: as NonEmptyList}

object SantaClaus extends StarterApp {
  opaque type Reindeer = Val[String]
  opaque type Elf      = Val[String]

  def vacation: Reindeer -⚬ Reindeer = λ { rndr =>
    rndr |> alsoPrintLine(r => s"$r going on vacation")
         |> delayValRandomMs(100, 200)
         |> alsoPrintLine(r => s"$r returned from vacation")
  }

  def makeToys: Elf -⚬ Elf = λ { elf =>
    elf |> alsoPrintLine(e => s"$e making toys")
        |> delayValRandomMs(30, 50)
        |> alsoPrintLine(e => s"$e needs consultation")
  }

  opaque type ReindeerGroup = Val[NonEmptyList[String]]
  opaque type ElfGroup      = Val[NonEmptyList[String]]

  object ReindeerGroup {
    def make: LList1[Reindeer] -⚬ ReindeerGroup = toScalaList1
    def ungroup: ReindeerGroup -⚬ LList1[Reindeer] = liftScalaList1
    def notifyReady: ReindeerGroup -⚬ (Ping |*| ReindeerGroup) = notifyVal
  }

  object ElfGroup {
    def make: LList1[Elf] -⚬ ElfGroup = toScalaList1
    def ungroup: ElfGroup -⚬ LList1[Elf] = liftScalaList1
    def notifyReady: ElfGroup -⚬ (Ping |*| ElfGroup) = notifyVal
  }

  def santa: Source[ReindeerGroup |+| ElfGroup] -⚬ Source[ReindeerGroup |+| ElfGroup] = {
    def deliverToys: ReindeerGroup -⚬ ReindeerGroup = alsoPrintLine[NonEmptyList[String]](grp => s"Delivering toys with ${grp.mkString(", ")}") > delayValRandomMs(50, 100)
    def meetInStudy:      ElfGroup -⚬ ElfGroup      = alsoPrintLine[NonEmptyList[String]](grp => s"Meeting in study with ${grp.mkString(", ")}") > delayValRandomMs(10, 20)

    def go: (ReindeerGroup |+| ElfGroup) -⚬ (Ping |*| (ReindeerGroup |+| ElfGroup)) =
      either(
        deliverToys > ReindeerGroup.notifyReady > snd(injectL),
        meetInStudy > ElfGroup.notifyReady > snd(injectR),
      )

    Source.mapSequence(go)
  }

  def pipeline(nCycles: Int): (LList[Reindeer] |*| LList[Elf]) -⚬ ((LList[Reindeer] |*| LList[Elf]) |*| Done) =
    λ { case reindeers |*| elves =>
      val rGrps = reindeers |> (LList.map(vacation) > LList.sortBySignal > Source.fromLList > Source.groups(9) > Source.map(ReindeerGroup.make))
      val eGrps = elves     |> (LList.map(makeToys) > LList.sortBySignal > Source.fromLList > Source.groups(3) > Source.map(ElfGroup.make))
      val pings |*| outGrps = (rGrps |*| eGrps) |> (Source.mergeEitherPreferred[ReindeerGroup, ElfGroup] > santa > Source.tapMap(notifyEither))
      val outRGs |*| outEGs = LList.partition(outGrps)
      val outRs = outRGs |> LList.flatMap(ReindeerGroup.ungroup > LList1.toLList)
      val outEs = outEGs |> LList.flatMap(ElfGroup.ungroup > LList1.toLList)
      (outRs |*| outEs) |*| (pings |> Source.take(nCycles) |> Source.drain)
    }

  def go(nCycles: Int): (LList[Reindeer] |*| LList[Elf]) -⚬ Done =
    λ { case reindeers |*| elves =>
      val promise |*| (returningReindeers |*| returningElves) = constant(demand[LList[Reindeer] |*| LList[Elf]])
      val rs = LList.concat(reindeers |*| returningReindeers)
      val es = LList.concat(elves |*| returningElves)
      val returningHelpers |*| done = pipeline(nCycles)(rs |*| es)
      done alsoElim supply(returningHelpers |*| promise)
    }

  override def blueprint: Done -⚬ Done =
    λ { case +(start) =>
      val reindeers = start |> constListOf1("R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9")
      val elves     = start |> constListOf1("E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "E10")
      go(nCycles = 20)(reindeers |*| elves)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy