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

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

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

import libretto.scaletto.StarterApp
import libretto.scaletto.StarterKit.{*, given}
import libretto.scaletto.StarterKit.Endless.{groupMap, mapSequentially, mergeEitherPreferred, take}
import libretto.scaletto.StarterKit.LList1.{closeAll, eachNotifyBy, foldMap, map, sortBySignal, transform, unzipBy}
import libretto.scaletto.StarterKit.Monoid.given
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")
  }

  class Group[A](
    getName   : A -⚬ (Val[String] |*| A),
    formatMsg : NonEmptyList[String] => String,
  )(using
    SignalingJunction.Positive[A],
  ) {
    opaque type Type = LList1[A |*| -[A]]

    def make: LList1[A |*| -[A]] -⚬ Type = id

    def act: Type -⚬ (Done |*| Type) =
      λ { as =>
        val names |*| as1 = unzipBy(fst(getName) > assocLR)(as) |> fst(toScalaList1)
        val +(done)       = names |> printLine(formatMsg) |> delayRandomMs(50, 100)
        val as2           = transform(useUntil)(done |*| as1)
        done |*| as2
      }

    def release: Type -⚬ One = foldMap(supply)

    private def useUntil: (Done |*| (A |*| -[A])) -⚬ (A |*| -[A]) =
      λ { case d |*| (a |*| nb) => a.waitFor(d) |*| nb }

    given Affine[Type] =
      Affine.from(foldMap(supply))

    given Signaling.Positive[Type] =
      Signaling.Positive.from(eachNotifyBy(fst(notifyPosFst[A]) > assocLR))
  }

  object RGroup extends Group[Reindeer](dup,names => s"Delivering toys with ${names.mkString(", ")}") {
    def deliverToys = act
  }

  object EGroup extends Group[Elf](dup, names => s"Meeting in study with ${names.mkString(", ")}") {
    def meetInStudy = act
  }

  import RGroup.{Type as RGroup, deliverToys}
  import EGroup.{Type as EGroup, meetInStudy}

  def santa(nCycles: Int): Endless[RGroup |+| EGroup] -⚬ Done = {
    def go: (RGroup |+| EGroup) -⚬ Done =
      either(
        deliverToys > elimSnd(RGroup.release),
        meetInStudy > elimSnd(EGroup.release),
      )

    mapSequentially(go) > take(nCycles) > LList.fold
  }

  override def blueprint: Done -⚬ Done =
    λ { case +(start) =>
      val reindeers : $[LList1[Reindeer]] = start |> constList1Of("R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9")
      val elves     : $[LList1[Elf]]      = start |> constList1Of("E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "E10")
      val reindeers1 = reindeers |> map(vacation) |> sortBySignal
      val elves1     = elves     |> map(makeToys) |> sortBySignal
      val rGroups |*| releasedReindeers = reindeers1 |> Endless.poolReset(vacation) |> fst(groupMap(9, RGroup.make))
      val eGroups |*| releasedElves     = elves1     |> Endless.poolReset(makeToys) |> fst(groupMap(3, EGroup.make))
      val groups: $[Endless[RGroup |+| EGroup]] = mergeEitherPreferred[RGroup, EGroup](rGroups |*| eGroups)
      joinAll(
        groups |> santa(nCycles = 20),
        closeAll(releasedReindeers),
        closeAll(releasedElves),
      )
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy