こんにちは!、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は単純で良いですね■