bjam AdC jp 2011 15日目
はてなさんは7時に日付変わるから遅れてない!
11日目あたりでruleの引数もsequenceだとか言ってましたけどその説明します。なんとか一日でも潰したいのでこの際ナンデモアリです。
rule
例えば適当なruleを書きます。
rule foo ( bar : baz ? : qux + : quux * : corge grault : garply waldo ? : fred plugh + : xyzzy thud * ) { .... }
ほげらー引数多いですね。が、何かおかしいです。いや、おかしくないです。でもなにか違和感です。
こんなめちゃくちゃなのは一旦保留して簡単なのから見てきます。
foo ruleの最初の方のやつ
rule one ( wibble ) rule zero-or-one ( wibble ? ) rule one-or-more ( wibble + ) rule zero-or-more ( wibble * )
rule名から大体想像できると思いますが、そんな感じです。それぞれwibbleは 1,0か1,1以上,0以上 の要素からなるsequenceです。
無名にすることもできますが、最後以外は1引数しか受け取りません。意味不明です。
rule zero-or-one ( ? ) rule one-or-more ( + ) rule zero-or-more ( * )
foo ruleの最後の方のやつ
foo ruleの引数は最後の方で変なのになってました。こんな感じ
rule foo ( ... : corge grault : garply waldo ? : fred plugh + : xyzzy thud * )
引数が2つあります。これはなんでしょう。
有り体に言えばこれはsequenceのパターンマッチです。って言うと分野の人から殺されそうですが勘弁してください。
で、sequenceモジュールのlessを思い出してください。
rule less ( a b )
おや!これは奇遇!
lessは2要素のsequenceを投げると大小関係を比較してくれるruleでした。つまり a は左 b は右の要素が格納されるということです。head tailのほうがわかり易いですかね。linked-listみたいです。
もちろんhead tailの2つだけでなくもっと増やすこともできますし、途中の引数をoptionalにすることもできます。
rule foo ( bar ? baz ? qux ? quux ? corge ? grault ? garply ? waldo ? fred ? plugh ? xyzzy ? thud ? ) { } foo foo foo foo foo foo foo foo foo foo foo foo foo ;
が、途中に + もしくは * があると、それ以降のすべての引数がその箇所に集約されるので気をつけてください。
rule always-error ( foo bar * not-match ) { } always-error hoge fuga piyo ; # => foo=fuga bar=>fuga,piyo
まーつまりheadとtailは
rule head ( h t * ) { return $(h) ; } rule tail ( h t * ) { return $(t) ; }
となります。
無名の引数はどうするねん
実は引数は名前をつける必要がありません。つまり無名の引数は捨てられるとかではなく実はあとから取得することができます。
rule unnamed ( * : * : * ) { ECHO $(1) ; ECHO $(2) ; ECHO $(3) ; } unnamed hoge fuga piyo : foo bar baz qux ; #=> hoge fuga piyo #=> foo bar baz qux #=>
まとめ
まにあったーーーー