こんにちは!、chibaです。
早くも書くネタが無いのですが、どうしたら良いんでしょうか。
今年の私のテーマは「挑戦」。
先日、そんな私にぴったりな、盗んだバイクで走り出したくなる挑戦をみつけました。
#!/usr/bin/perl # PerlとC++は世界一。 srand(time); my $a = 0; my $b = 0; for(my $i = 0; $i < 1000; $i++) { (rand(2)<1 ? $a : $b) += 1; } print "$a, $b\n"
これをPerlや、C++以外の言語で書けるのか、と。
私は、LISP野郎なのでLISPで回答するとして考えましたが「実行時に変数の名前によって任意の変数にアクセスし、その変数に値を代入できるか」という風にお題を解釈しました。
PerlやC++の場合は、?:にそういう機能があるのでしょう。
Common Lispだとどうなるかというと、「実行時に変数の名前によって任意の変数にアクセス」というのは、シンボル名による変数へのアクセスで可能なので、上をCommon Lispに訳すと
(let ((a 0) (b 0)) (declare (special a b)) (dotimes (i 1000) (incf (symbol-value (if (< (random 2) 1) 'a 'b)))) (format t "~A, ~A~%" a b)) ;⇒ NIL ---------- 499, 501
こんな感じに書くことになるのかなあと思いました。
…というようなことをtaharaさんと昼食時に話していたのですが、taharaさん曰くifにsetfが付いてれば可能なんじゃないかとのこと。
なるほど、確かにそうです。
setfというのは代入する構文のマクロなのですが、ユーザーが色々カスタマイズできます。
実行時に変数名でアクセス→代入というのではなく、そういう構文をマクロで定義するわけですね。
ユーザーがifにsetfを書けば良いのですが、これが標準で付いている処理系をどっかでみたなーと思ったので調べてみるとCLISPがそうでした。
CLISPだと標準で
(let ((a 0) (b 0)) (dotimes (i 1000) (incf (if (< (random 2) 1) a b))) (format t "~A, ~A~%" a b)) ;⇒ NIL ---------- 513, 487
と書けます。自分はPerlは書けないのですが、+=をカスタマイズすることによって
for(my $i = 0; $i < 1000; $i++) { if (rand(2) < 1) { $a } else { $b } += 1; }
のようにも書けるようにユーザーが勝手に定義できる、という感じでしょうか。
こんなことをしているとすぐカオスになりそうですが、LISPに構文は無いようなものなので特に混乱もなかったりします。LISPは単純で良いですね■