Scalaでパーサーを作ってみる〜11:関数リテラル

Scalaの勉強をはじめたので、とりあえず簡単なパーサーを作ってみてます。
http://d.hatena.ne.jp/nowokay/20111109#1320815540


前回でレキシカルスコープとクロージャを導入しました。
http://d.hatena.ne.jp/nowokay/20111115#1321333375


ときたら、関数リテラルを使いたくなります。
やりましょう。


「{引数 => 処理}」という形で関数が書けるように構文を定義します。

  //funcLiteral ::= "{" [[ident {"," ident}] "=>"] lines "}"
  def funcLiteral: Parser[AST] = "{"~>opt(repsep(ident, ",")<~"=>")~lines<~"}"^^{
    case p~x => {
        p match{
          case Some(param) => Func(param.map(_.name), x)
          case None => x
        }
    }
  }

「=>」が来たら関数リテラルで、こなかったらブロックということにしてます。


これはfactorとして扱えるようにしましょう。

  //factor ::= intLiteral | stringLiteral | "(" expr ")" |funcLiteral
  def factor: Parser[AST] = intLiteral | stringLiteral | ident |
    "("~>expr<~")" | funcLiteral


あとは、構文処理のときにその時点での環境と一緒にクロージャとしてまとめます。

        case f:Func =>{
            Closure(env, f)
        }


そしたら、こういう感じで関数を扱えるようになります。

val fl = {x => x + 10};
println(fl(3));


もちろん関数をそのまま実行させることもできます。

println({x, y => x * y}(3, 4));


あと、こういう感じで2パラメータの関数のカリー化もできてます。

def high(x) ={y => x * y};
val m3 = high(3);
val m4 = high(4);
println(m3(5));
println(m4(5));

というか、この子かわいい!
なんかできる子になってる!


そうすると、次のようにfor文も書けます。

def for(start, end, proc)={
    def impl(i)={
      if(i < end + 1){
        proc(i);
        impl(i + 1)
      }else{
        0
      }
    };
    impl(start)
};

for(2, 5, {i => 
    println(i);
    println(i * 2)
});

なんか、実行サンプルがまともなプログラムになってきました!


データ構造がない気もしますが、大丈夫。

def array3(x, y, z) = {idx => 
  if(idx < 1) x 
  else if(idx < 2) y 
  else z
};
val ar = array3(11, 13, 17);
println(ar(2) + ":" + ar(1) + ":" + ar(0));

こんな感じで、3要素の配列が定義できちゃいます!
できる子ですから!
あとは適当に組み合わせれば、どんなデータ構造も実現できるってわけです。


ソースはこれです。
https://gist.github.com/1345875/7cc5b01c802f43d0a1482c720792566d9ab91ec9