Skip to content

Instantly share code, notes, and snippets.

@zainab-ali
Last active July 10, 2023 19:07
Show Gist options
  • Save zainab-ali/c841785b5f6d7fb3297727508d5f5933 to your computer and use it in GitHub Desktop.
Save zainab-ali/c841785b5f6d7fb3297727508d5f5933 to your computer and use it in GitHub Desktop.
Simplified pull free monad without type parameters or overt reference to monads
enum Pull {
case Done
case Output(name: String)
case UnconsThen(pull: Pull, f: Option[(String, Pull)] => Pull)
case Then(pull: Pull, next: () => Pull)
}
import Pull._
val done = Done
def single(name: String) = Output(name)
def append(pull: Pull, name: String) = Then(pull, () => single(name))
def repeat(pull: Pull): Pull = Then(pull, () => repeat(pull))
def take(n: Int, pull: Pull): Pull = {
def onOutput(element: Option[(String, Pull)]): Pull =
element match {
case Some((name, rest)) =>
Then(
Output(name),
() => take(n - 1, rest)
)
case None => done
}
if n <= 0 then done else UnconsThen(pull, onOutput)
}
def step(pull: Pull): Either[(String, Pull), Unit] =
pull match {
case Done => Right(())
case Output(name) => Left((name, done))
case UnconsThen(pull, f) =>
step(pull) match {
case Left((name, next)) =>
step(f(Some((name, next))))
case Right(a) =>
step(f(None))
}
case Then(pull, rest) =>
step(pull) match {
case Left((name, next)) =>
Left((name, Then(next, rest)))
case Right(()) => step(rest())
}
}
def last(pull: Pull, prev: Option[String]): Option[String] = step(
pull
) match {
case Left((name, next)) => last(next, Some(name))
case Right(()) => prev
}
val kittens = append(single("Mao"), "Popcorn")
println(last(take(4, repeat(kittens)), None))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment