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

libretto.examples.sunflowers.SunflowerProcessingFacility.scala Maven / Gradle / Ivy

The newest version!
package libretto.examples.sunflowers

import libretto.scaletto.StarterKit.*
import libretto.stream.scaletto.DefaultStreams.ValSource
import libretto.stream.scaletto.DefaultStreams.ValSource.{Polled, fromChoice, notifyAction, poll}

object SunflowerProcessingFacility {
  def blueprint: ValSource[Sunflower] -⚬ (ValSource[SeedsPack] |*| ValSource[OilBottle]) = rec { self =>
    λ { sunflowers =>
      // give names to the outputs
      producing { case seedsOut |*| oilOut =>
        // race the outputs by which one acts (i.e. pulls or closes) first
        (selectBy(notifyAction, notifyAction) >| (seedsOut |*| oilOut)) choose {
          // seed output acted first
          case Left (seedsOut |*| oilOut) =>
            (fromChoice >| seedsOut) choose {
              case Left(closingSeeds) =>
                returning(
                  oilOut       := sunflowers |> oilOnlyMode,
                  closingSeeds := constant(done),
                )
              case Right(pullingSeeds) =>
                (pullingSeeds |*| oilOut) :=
                  switch ( pull3(sunflowers) )
                    .is { case InR(sunflower3 |*| sunflowers) =>
                      // got 3 sunflowers, let's roast the seeds and package them
                      val seedsPack = roastSeedsAndPack(sunflower3)
                      // operate recursively on the rest of the input source
                      val seedsPacks |*| oilBottles = self(sunflowers)
                      Polled.cons(seedsPack |*| seedsPacks) |*| oilBottles
                    }
                    .is { case InL(+(closed)) =>
                      // no more sunflowers
                      Polled.empty(closed) |*| ValSource.empty(closed)
                    }
                    .end
            }
          // oil output acted first
          case Right(seedsOut |*| oilOut) =>
            (fromChoice >| oilOut) choose {
              case Left(closingOil) =>
                returning(
                  seedsOut   := sunflowers |> seedsOnlyMode,
                  closingOil := constant(done),
                )
              case Right(pullingOil) =>
                (seedsOut |*| pullingOil) :=
                  switch ( pull5(sunflowers) )
                    .is { case InR(sunflower5 |*| sunflowers) =>
                      val oilBottle = makeOil(sunflower5)
                      val seedsPacks |*| oilBottles = self(sunflowers)
                      seedsPacks |*| Polled.cons(oilBottle |*| oilBottles)
                    }
                    .is { case InL(+(closed)) =>
                      ValSource.empty(closed) |*| Polled.empty(closed)
                    }
                    .end
            }
        }
      }
    }
  }

  private def oilOnlyMode: ValSource[Sunflower] -⚬ ValSource[OilBottle] = rec { self =>
    λ { sunflowers =>
      producing { oilOut =>
        (fromChoice >| oilOut) choose {
          case Left(closing) =>
            closing := ValSource.close(sunflowers)
          case Right(pulling) =>
            pulling := switch ( pull5(sunflowers) )
              .is { case InL(closed)      => Polled.empty(closed) }
              .is { case InR(sf5 |*| sfs) => Polled.cons(makeOil(sf5) |*| self(sfs)) }
              .end
        }
      }
    }
  }

  private def seedsOnlyMode: ValSource[Sunflower] -⚬ ValSource[SeedsPack] = rec { self =>
    λ { sunflowers =>
      producing { seedsOut =>
        (fromChoice >| seedsOut) choose {
          case Left(closing) =>
            closing := ValSource.close(sunflowers)
          case Right(pulling) =>
            pulling := switch ( pull3(sunflowers) )
              .is { case InL(closed)      => Polled.empty(closed) }
              .is { case InR(sf3 |*| sfs) => Polled.cons(roastSeedsAndPack(sf3) |*| self(sfs)) }
              .end
        }
      }
    }
  }

  private type Sunflower3 = (Sunflower, Sunflower, Sunflower)
  private type Sunflower5 = (Sunflower, Sunflower, Sunflower, Sunflower, Sunflower)

  private def pull3: ValSource[Sunflower] -⚬ (Done |+| (Val[Sunflower3] |*| ValSource[Sunflower])) =
    λ { src =>
      switch ( poll(src) )
        .is { case InL(closed) => InL(closed) }
        .is { case InR(sf1 |*| tail) =>
          switch ( poll(tail) )
            .is { case InL(closed) => InL(joinAll(neglect(sf1), closed)) }
            .is { case InR(sf2 |*| tail) =>
              switch ( poll(tail) )
                .is { case InL(closed) => InL(joinAll(neglect(sf1), neglect(sf2), closed)) }
                .is { case InR(sf3 |*| tail) => InR(tuple(sf1, sf2, sf3) |*| tail) }
                .end
            }.end
        }.end
    }

  private def pull5: ValSource[Sunflower] -⚬ (Done |+| (Val[Sunflower5] |*| ValSource[Sunflower])) =
    λ { src =>
      switch ( pull3(src) )
        .is { case InL(closed) => InL(closed) }
        .is { case InR(sf3 |*| tail) =>
          switch( poll(tail) )
            .is { case InL(closed) => InL(joinAll(neglect(sf3), closed)) }
            .is { case InR(sf4 |*| tail) =>
              switch( poll(tail) )
                .is { case InL(closed) => InL(joinAll(neglect(sf3), neglect(sf4), closed)) }
                .is { case InR(sf5 |*| tail) =>
                  val res = tuple(sf3, sf4, sf5) |> mapVal { case ((s1, s2, s3), s4, s5) => (s1, s2, s3, s4, s5) }
                  InR(res |*| tail)
                }.end
            }.end
        }.end
    }

  private def roastSeedsAndPack: Val[Sunflower3] -⚬ Val[SeedsPack] =
    mapVal(_ => SeedsPack())

  private def makeOil: Val[Sunflower5] -⚬ Val[OilBottle] =
    mapVal(_ => OilBottle())
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy