Skip to content

Instantly share code, notes, and snippets.

@Kazark
Created March 19, 2021 14:45
Show Gist options
  • Save Kazark/84a0ce57e04b7ec2572f4dc55e790cdf to your computer and use it in GitHub Desktop.
Save Kazark/84a0ce57e04b7ec2572f4dc55e790cdf to your computer and use it in GitHub Desktop.
Monad as a value versus as part of the language semantics (in Scala)
(setq org-confirm-babel-evaluate nil)
(setq org-babel-scala-command "/usr/local/Cellar/dotty/3.0.0-RC1/bin/scala")
(setq org-babel-scala-wrapper-method "%s")
(unless (boundp 'org-babel-scala-evaluate)
  (load-file "~/.emacs.d/ob-scala.el"))
object Nothing extends RuntimeException

object Maybe:
  def nothing = throw Nothing
  def guard(cond: Boolean): Unit =
    if !cond then nothing
  def guardNot(cond: Boolean): Unit =
    if cond then nothing

object Parse:
  def int(x: String) =
    x.toIntOption.getOrElse(Maybe.nothing)

object Status:
  def strUncons(x: String): (Char, String) =
    Maybe.guard(x.length > 0)
    (x(0), x.substring(1))

  def truncateAt(c: Char, s: String): String =
    val index = s.indexOf(c)
    Maybe.guard(index >= 0)
    s.substring(0, index)

  def splitIn2(c: Char, s: String): (String, String) =
    val ss = s.split(c)
    Maybe.guard(ss.length == 2)
    (ss(0), ss(1))

  def parse(s: String): (Int, Int) =
    val firstCharAndRest = strUncons(s)
    Maybe.guard(firstCharAndRest._1 == '[')
    val xOfY = truncateAt(']', firstCharAndRest._2)
    val xAndY = splitIn2('/', xOfY)
    val x = Parse.int(xAndY._1)
    val y = Parse.int(xAndY._2)
    (x, y)

@main
def main(): Unit =
  try
    val (x, y) = Status.parse("[3/32] Monads!!")
    println(s"$x of $y")
  catch
    case Nothing => println("Unable to parse.")
type Maybe[A] = Option[A]

object Maybe:
  val nothing = None
  def guard(cond: Boolean): Maybe[Unit] =
    if cond then Some(()) else nothing
  def guardNot(cond: Boolean): Maybe[Unit] =
    if cond then nothing else Some(())

object Status:
  def strUncons(x: String): Maybe[(Char, String)] =
    for () <- Maybe.guard(x.length > 0)
    yield (x(0), x.substring(1))


  def truncateAt(c: Char, s: String): Maybe[String] =
    val index = s.indexOf(c)
    for () <- Maybe.guard(index >= 0)
    yield s.substring(0, index)

  def splitIn2(c: Char, s: String): Maybe[(String, String)] =
    val ss = s.split(c)
    for () <- Maybe.guard(ss.length == 2)
    yield (ss(0), ss(1))

  def parse(s: String): Maybe[(Int, Int)] =
    for
      firstCharAndRest <- strUncons(s)
      () <- Maybe.guard(firstCharAndRest._1 == '[')
      xOfY <- truncateAt(']', firstCharAndRest._2)
      xAndY <- splitIn2('/', xOfY)
      x <- xAndY._1.toIntOption
      y <- xAndY._2.toIntOption
    yield (x, y)

@main
def main(): Unit =
  Status.parse("[3/32] Monads!!") match
    case None => println("Unable to parse.")
    case Some((x, y)) => println(s"$x of $y")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment