Twitterを眺めていたらネタに出会ったので書いてみました。
(defmacro switch (val &body clauses)
(let ((syms (loop :repeat (length clauses)
:collect (gensym))))
`(tagbody
(case ,val
,@(mapcar
#'(lambda (clause sym)
`(,(car clause) (go ,sym)))
clauses
syms))
,@(mapcan
#'(lambda (clause sym)
`(,sym ,@(cdr clause)))
clauses
syms)
break)))
switchのclauses部にはCommon Lispのcaseと同様の式を書くことができます。
caseと異なるのは、条件に一致した場合goで目的の処理の前に飛ぶところです。このため、明示的に(go break)としない限り、一致した箇所以降の式をすべて実行します。
また、caseと異なり、tagbodyに展開するため返り値は常にnilになります。
;; 例
(switch 2
(2 (print 2) (go break))
(3 (print 3))
(4 (print 4)))
2
=> nil
(switch 3
(2 (print 2) (go break))
(3 (print 3))
(4 (print 4)))
3
4
=> nil
0 件のコメント:
コメントを投稿