しょーもない再起動の使い方: typo
"apply" をよく "appyl" と typo して undefined-function とか怒られるので、もうちょっと気を利かせてくれないかな、とこんなことをした。
(defun appyl (fn &rest args) (restart-case (error 'undefined-function :name 'appyl) (apply () :report "「ごめんなさい、また typo しました。apply してください」" (apply #'apply fn args)))) => appyl
これで typo して undefined-function と怒られた時に apply 再起動を選べばそのまま apply してくれる。
ついでなので一般化してみた。
;; xyzzy でやってるのでこうだけど、common-lisp だとちょっと syntax が違ったはず (define-condition typo (program-error) (name) (:report (lambda (typo stream) (format stream "Oh, typo... ~S" (typo-name typo))))) (defmacro deftypo (typo correct) `(defun ,typo (&rest args) (restart-case (error 'typo :name ',typo) (correct () :report (lambda (stream) (format stream "Invoke correct function `~S'." ',correct)) (apply ',correct args)))))
(deftypo appyl apply) => appyl (appyl (lambda (a b) (+ a b)) '(1 3)) ; typo: ; Oh, typo... appyl ; ; 0 [correct ] Invoke correct function `apply'. ; 1 [abort ] やめる。 ; ; Restart[0-1]: 0 => 4
ぉぅぃぇ。
いちいち再起動選ぶのもめんどいので warning 出しつつ勝手に修正するマクロも。
(define-condition typo-corrected (warning) (name) (:report (lambda (typo-corrected stream) (format stream "typo `~S' auto corrected." (typo-corrected-name typo-corrected))))) (defmacro with-auto-correct-typos (&body body) `(handler-bind ((typo (lambda (typo) (warn 'typo-corrected :name (typo-name typo)) (let ((r (find-restart 'correct typo))) (when r (invoke-restart r)))))) ,@body))
と思ったけど condition-restart のだと warning でも再起動選択が出てきてしまった。ぐむむ。
(with-auto-correct-typos (appyl (lambda (x) (* x x)) '(3))) ; typo-corrected: ; typo `appyl' auto corrected. ; ; 0 [muffle-warning] この警告は無かったことに。 ; 1 [abort ] やめる。 ; ; Restart[0-1]: 0 => 9