Skip to content

Instantly share code, notes, and snippets.

@kory33
Created January 18, 2026 23:03
Show Gist options
  • Select an option

  • Save kory33/258c2eecc01a925df2adc93561b0048a to your computer and use it in GitHub Desktop.

Select an option

Save kory33/258c2eecc01a925df2adc93561b0048a to your computer and use it in GitHub Desktop.
An exotic instance for Writer-like Eff datatype
enum Executable[Instr[_], ExitCode]:
case Exit[I[_], EC](
code: EC
) extends Executable[I, EC]
case NonEmpty[I[_], BranchIndex, EC](
headInstruction: I[BranchIndex],
branches: BranchIndex => Executable[I, EC]
) extends Executable[I, EC]
import Executable.*
extension [F[_], A](exe: Executable[F, A])
def replaceExits[B](
replacementRule: A => Executable[F, B]
): Executable[F, B] =
exe match
case Executable.NonEmpty(head, rest) =>
// すべての分岐先について再帰的に置換を行っていく
Executable.NonEmpty(head, b => rest(b).replaceExits(replacementRule))
case Executable.Exit(ec) =>
// 置換個所(Exitノード)に到達したので置換する
replacementRule(ec)
enum WriteOne[Res, BI]:
case Output[R](result: R) extends WriteOne[R, Unit]
type WriteInstr[R] = [A] =>> WriteOne[R, A]
extension [Res, A](exe: Executable[WriteInstr[Res], A])
// プログラム全体のexit codeを(プログラム構造を覗くことで)取り出す
def extractResult: A =
exe match
case Exit(a) => a
case NonEmpty(WriteOne.Output(_), branches) => branches(()).extractResult
def swapMap[B](rule: A => Executable[WriteInstr[Res], B]) =
val nextProg = rule(exe.extractResult)
val overallRes = nextProg.extractResult
nextProg.replaceExits(_ => exe.replaceExits(_ => Exit(overallRes)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment