Fruitful

Fruitful expresses a weaker guarantee than Fn: the stage always returns Yield.Some, but it is free to choose any status and any evolution. The return type of apply is narrowed to Yield.Some[I, O, E] so the compiler can track this guarantee statically, making Fruitful stages safe to use wherever an output value is always expected.

import h8io.stages.*
import h8io.stages.base.*
object Loudify extends Fruitful.Endo[String, Nothing] with SAMStage.Endo[String, Nothing] {
  override def apply(in: String): Yield.Some[String, String, Nothing] =
    Yield.Some(in.toUpperCase + "!", Status.Success, this)
}

Loudify("hello")
// res0: Yield.Some[String, String, Nothing] = Some(
//   out = "HELLO!",
//   status = Success,
//   evolution = <function1>
// )

Fruitful is useful for binary operators that need to guarantee both branches always produce output, or for stages that always yield a value but may still signal errors or transition to a different stage.