昨日の Haskell 版 Unlambda を Scala で書いてみた

久しぶりに Scala ネタ。

ほぼ、昨日のまんま。やっぱり .x, r, s, k, i だけ。

object Unlambda {
  abstract class Tree[T]
  case class Leaf[T](elm:T) extends Tree[T]
  case class Branch[T](l:Tree[T], r:Tree[T]) extends Tree[T]

  class Func(f:Func => Func) {
    def apply(g:Func):Func = f(g)
  }

  def p(c:Char):Func = new Func((f) => {print(c); f})
  val r:Func = p('\n')
  val s:Func = new Func((f) => new Func((g) => new Func((h) => (f(h))(g(h)))))
  val k:Func = new Func((f) => new Func((g) => f))
  val i:Func = new Func((f) => f)

  def parse(cs:List[Char]):Tree[Func] = {
    def parse_aux(cs:List[Char]):Option[(Tree[Func], List[Char])] = cs match {
      case '`'::cs =>
        parse_aux(cs).flatMap((p) => p match {
          case (l, cs) => parse_aux(cs).flatMap((p) => p match {
            case (r, cs) => Some((Branch(l, r), cs))
          })
        })
      case '.'::c::cs => Some((Leaf(p(c)), cs))
      case 'r'::cs    => Some((Leaf(r), cs))
      case 's'::cs    => Some((Leaf(s), cs))
      case 'k'::cs    => Some((Leaf(k), cs))
      case 'i'::cs    => Some((Leaf(i), cs))
      case c::cs if (c.isWhitespace) => parse_aux(cs)
      case _ => None
    }

    parse_aux(cs) match {
      case Some((t, Nil)) => t
      case Some((t, rest)) if (rest.forall(_.isWhitespace)) => t
      case _ => throw new RuntimeException
    }
  }

  def eval(t:Tree[Func]):Func = t match {
    case Leaf(f) => f
    case Branch(l, r) => (eval(l))(eval(r))
  }

  def main(args:Array[String]) {
    eval(parse(scala.io.Source.fromFile(args(0)).toList))
  }
}

相変わらず、ファイル入出力が分かりません。だれかイディオムでもまとめてないかしら。

追記

そういえば今更だけど、Scala で Unlambda といえば id:yukoba さんが書かれています。

Unlambda on Scala - yukobaのブログ

追記 2010-09-07

Monadについて - NoisySpot/メモ帳 を読んで、ふとこの Unlambda サブセットのことを思い出したので、誰か教えてくれないかなー、と、ちょっと呟いてみた。

2人もお返事くれました。

Haskell の do 構文とほとんど同じノリですね。