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

libretto.examples.canteen.Protocol.scala Maven / Gradle / Ivy

The newest version!
package libretto.examples.canteen

import libretto.scaletto.StarterKit.*
import libretto.scaletto.StarterKit.scalettoLib.given

object Protocol {
  /** Interface of a canteen for one session.
    * The canteen facility is to the left of this interface,
    * whereas the customer is to the right.
    *
    * The session starts in the soup section.
    */
  opaque type Session = SectionSoup
  object Session {
    def proceedToSoups: Session -⚬ SectionSoup =
      id

    def create: SectionSoup -⚬ Session =
      id
  }

  /** In this section, the customer has the option to get a soup or to move down the line to the next section.
    * In fact, they may get multiple soups, but also no soup if there is none left.
    */
  type SectionSoup = Rec[ [SectionSoup] =>> // recursive types have to be defined using the `Rec` operator
    |&| [ // `|&|` means consumer choice: the party to the right (the "consumer", in our case the customer) chooses the branch

      // Option 1:
      //   Try to get a soup (if there's any left) and remain in this section (to get an opportunity to get another soup).
      //   `|+|` means producer choice: the party to the left (the "producer", in our case the canteen facility) chooses the branch.
      //   Here, the facility chooses whether there is any soup left, or the customer has to proceed (without soup) to the next section.
      (Soup |*| SectionSoup) |+| SectionMain,

      // Option 2:
      //   Proceed to the next section.
      SectionMain,
    ]
  ]

  object SectionSoup {
    private def pack: (((Soup |*| SectionSoup) |+| SectionMain) |&| SectionMain) -⚬ SectionSoup =
      dsl.pack[[S] =>> ((Soup |*| S) |+| SectionMain) |&| SectionMain]

    def from[A](
      onSoupRequest : A -⚬ ((Soup |*| SectionSoup) |+| SectionMain),
      goToMainDishes: A -⚬ SectionMain,
    ): A -⚬ SectionSoup =
      choice(onSoupRequest, goToMainDishes) > pack

    def getSoup: SectionSoup -⚬ ((Soup |*| SectionSoup) |+| SectionMain) =
      unpack > chooseL

    def proceedToMainDishes: SectionSoup -⚬ SectionMain =
      unpack > chooseR
  }

  /** In this section, the customer has the option to get the main dish.
    * As with soup, the customer may get multiple main dishes. There's no variety though, to keep things simple.
    * The customer no longer has the possibility to ask for soup, as they have already left the soup section.
    */
  type SectionMain = Rec[ [SectionMain] =>>
    |&| [
      // Option 1: Try to get the main dish (if there's any left).
      // If successful, remain in the main dish section, otherwise, proceed to the payment section.
      (MainDish |*| SectionMain) |+| SectionPayment,

      // Option 2: Proceed to the payment section.
      SectionPayment,
    ]
  ]

  object SectionMain {
    def from[A](
      onDishRequest: A -⚬ ((MainDish |*| SectionMain) |+| SectionPayment),
      goToPayment  : A -⚬ SectionPayment,
    ): A -⚬ SectionMain =
      λ { a => pack(choice(onDishRequest, goToPayment)(a)) }

    def getMainDish: SectionMain -⚬ ((MainDish |*| SectionMain) |+| SectionPayment) =
      unpack > chooseL

    def proceedToPayment: SectionMain -⚬ SectionPayment =
      unpack > chooseR
  }

  type SectionPayment =
    PaymentCard =⚬ PaymentCard // The cashier borrows customer's payment card and always returns it back.

  opaque type Soup     = Val["Soup"]
  opaque type MainDish = Val["MainDish"]

  def makeSoup: Done -⚬ Soup =
    printLine("Cooking soup") > constVal("Soup")

  def makeMainDish: Done -⚬ MainDish =
    printLine("Cooking main dish") > constVal("MainDish")

  def eatSoup: Soup -⚬ Done =
    printLine(soup => s"Eating $soup")

  def eatMainDish: MainDish -⚬ Done =
    printLine(dish => s"Eating $dish")

  opaque type PaymentCard = Val[String]

  object PaymentCard {
    def issue: Done -⚬ PaymentCard =
      constVal("1234 5678 9876 5432")

    def shred: PaymentCard -⚬ Done =
      neglect

    given SignalingJunction.Positive[PaymentCard] =
      signalingJunctionPositiveVal[String]
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy