@shtaxxxがFizzBuzzでコードゴルフをやっているのを見かけた.気分転換に私もやってみようと思ったけど,コードゴルフはよく分からないので記号プログラミングでやってみた.
以下は1から100までのFizzBuzz.Ruby1.9以降で実行できる.
$____="#"=~/$/;$___=$____+$____;$_=$____+$___;$__=$___+$_;$_____=$___+ $__;@@_=""<<($_*$_*$_____+$_); @@__=""<<($___*$__*$_____);@__=""<<($_* $__*$_____); @___=""<<($__**$_-$___**$_);@_=""<<($__**$_-$_);@_<<@_;__= ->(_){_>$____&&__.(_-$____);($><<[_%$_<$____?(@@__+@__+@_):_%$__>(""=~ //)?_:'',[@@_+@___+@_][_%$__]]*''+(""<<($___*$__)))};__.($___*$___*$__*$__)
誰がどう見てもFizzBuzzのコードである.
出力は以下の通り.普通のFizzBuzz.
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz (略)
上のコードの処理の順番は以下の通り.
- 数値を変数に代入
- 文字(列)を変数に代入
- ->(){}で再帰lambdaを作成
- lambdaを実行
何が何だか分からない人向け解説
以下のことさえ押さえておけば上のコードを読めるはず.
変数
変数名は_とか__とか$_とか@_とか@@_といった具合に_と$と@の組み合わせになっている.ちなみに上のコードでは,__はlambda,$_で始まる変数は数値,@_と@@_で始まる変数は文字(列)を保持している.また,_はlambdaの仮引数として使っている.なるべくコードが短くなるように使用頻度が高い変数には短い名前を付けるようにしている(つもり).
数値
"#"=~/$/,"##"=~/$/でそれぞれIntegerの1,2が得られる.あとは加減乗除すれば任意の値が作れる.
文字
"" << (文字のASCIIコード)で対応する文字のStringが得られる.例えば"" << 65は"A"となる.
処理の繰り返し
Ruby1.9以降ではlambda{|x| ...}を->(x){...}のように記号だけで書けるので,lambdaで再帰処理を書けばループが実現できる.例えば __ = ->(_){ __.(_) }とすれば無限再帰するlambdaが作れる.
出力
組み込み変数の$>が$stdoutに対応しているので,$> << "hello, world!\n"のようにすれば記号だけで標準出力に文字列を出力できる.
以上
Ruby1.9で記号だけでlambdaが書けるようになったのは非常に素晴らしい.あとは記号だけでevalができれば文句ないんだけど….