#(define a 1)
(define b 2)
(define c 3)
(cond
((= expr a) (do-something-a))
((= expr b) (do-something-b))
((= expr c) (do-something-c))
)
#これを case や match のように expr を何度も書かないですっきり書く方法はありますか?
#(case expr
((a) (do-something-a))
((b) (do-something-b))
((c) (do-something-c))
)
#だと a b c がシンボル扱いになってうまくいかないです。
#そういうことよくありますよね。とりあえずは、Gaucheのcompile.scmに、case/unquoteというマクロが定義されているので、それをコピーして使えば目的のことが素直に表現できると思います。
#他には、
#((cdr (assv expr `((,a . ,do-something-a)
(,b . ,do-something-b)
(,c . ,do-something-c)))))
#と書くとか。
#みんなどうしているんだろう?
#できました!ありがとうございます。マクロを使わない標準的な方法があるのかと思いましたが、やっぱりマクロが必要なんですね。
#標準で用意するほど用法が固まってない、というのが標準にない理由かなと思います。
#a,b,cをいつ評価すべきか (caseに入った時に毎回? それとも定数式で一回限り?)、とか比較関数に何を使うか、とか。
#ただ、実はCommon Lispだと定数式で良ければ #. が使えるので、比較関数がeqv? (CLならeql) で良ければ標準のcaseだけで済むんですね。
#(case form
((#.a) (do-something-a))
((#.b) (do-something-b))
((#.c) (do-something-c)))
#Schemeのセマンティクスではread-timeがCLよりも厳密に分かれている、#. をそのまま持ち込むのは無理があり、かといってcaseナンチャラを増やすのも
#綺麗じゃないし… というわけで「いい案が思いつかないので標準になってない」という方が大きいかも。
#なるほど。
#ちなみに clojure には condp があるのでこう書けますね
#(condp = expr
a (do-something-a)
b (do-something-b)
c (do-something-c))
#比較関数を指定可能にするcase/cmpってのは考えたことあります。(case/cmp expr = ((item ...) expr ...) ...)
#ただこれもitem...はリテラルじゃないとだめか。
#clojureのはa,b,cが評価されるってのと引換えに、複数のitemがマッチする場合が書きにくくなってるんだな。
#うーん、でも case/unquote 相当のものは組み込みで欲しいと思うことがよくあります。Scheme外の関数を呼び出したりすると戻り値がコードで返ってくるので、毎回マクロで定義するのもなあ、と思います。ただ、他に使う局面があまり思いつかない。
#Schemeの枠内だとシンボルが使えるので、caseでいいんですが。
#case/unquoteの良いところは、a,b,cの部分がコンパイル時に決まる定数の場合、コンパイル後の効率が通常のcase文と同じになるってところなんですね。確かにCでswitch文に定数を使うのと同じように使いたいことって結構あるんで、需要は高いかも。
#あと「文字に対応するコード」でディスパッチしたい場合なんかも。
#上のcondpなんかはもう少しリベラルで、a,b,cが毎回計算されますね。まあコンパイラが賢ければ定数かどうかは判断できるか…
##サイレンが鳴ってる
#かなりデカイ地震ですね
#うお。大丈夫なんでしょうか。
##第1波はもう来たのか。
#特に混乱は無かったです。ワイキキは一部のホテルが避難地域だったので、旅行者の人たちは朝から避難したり大変だったかも。うちのまわりも交通規制がかかったので異様に静かでした。
#津波は観測されたけれど、被害が出るほど大きくはならなかったようです。