C風switchをgoを使わない形に書き直して見ました。
caseの実行する式の部分に、後続で処理するすべての式をぶち込んでいます。
今回は明示的にブロックを抜けない限り、最後に評価された値が返ります。
(defmacro switch-2 (val &body clauses)
(let ((break (gensym)))
`(block ,break
(macrolet ((break-switch ()
`(return-from ,',break nil)))
(case ,val
,@(maplist
#'(lambda (rest)
`(,(caar rest) ,@(loop :for i in rest
:append (cdr i))))
clauses))))))
;; example
(switch-2 2
(2 (print 2))
(3 (print 3) (break-switch))
(4 (print 4)))
loopマクロの箇所は、最初はmapcanで書いていたのですが、なぜか処理が止まったので書き換えました。 mapcanが破壊的関数なため、maplistで段階的にアクセスしているリストの構造(clausesの一部)を変更してしまっているのだろうと思っています。
mapcanの非破壊版くらい仕様に入れておいて欲しかったです。
0 件のコメント:
コメントを投稿