常見的巨集觀模式
TODO:也許將解釋移到備註並單獨新增示例
FOOF
在 Common Lisp 中,有一個廣義引用的概念。它們允許程式設計師將值設定為各種位置,就好像它們是變數一樣。使用此功能的巨集通常在名稱中使用 F
-postfix。這個地方通常是巨集的第一個引數。
標準的例子: INCF
,DECF
, ROTATEF
, SHIFTF
, REMF
。
一個愚蠢的例子,一個在一個地方翻轉數字商店標誌的巨集:
(defmacro flipf (place)
`(setf ,place (- ,place)))
WITH-FOO
獲取並安全釋放資源的巨集通常以 WITH-
字首命名。巨集應該通常使用如下語法:
(with-foo (variable details-of-the-foo...)
body...)
標準示例: WITH-OPEN-FILE
, WITH-OPEN-STREAM
, WITH-INPUT-FROM-STRING
, WITH-OUTPUT-TO-STRING
。
實現這種型別的巨集的一種方法是首先實現功能版本,這種方法可以避免名稱汙染和無意識的多重評估的一些缺陷。例如,實現安全建立視窗小部件並在之後清理的 with-widget
巨集的第一步可能是一個函式:
(defun call-with-widget (args function)
(let ((widget (apply #'make-widget args))) ; obtain WIDGET
(unwind-protect (funcall function widget) ; call FUNCTION with WIDGET
(cleanup widget) ; cleanup
因為這是一個函式,所以不用擔心函式或供應商中的名稱範圍,並且可以很容易地編寫相應的巨集:
(defmacro with-widget ((var &rest args) &body body)
`(call-with-widget (list ,@args) (lambda (,var) ,@body)))
DO-FOO
迭代某些東西的巨集通常用 DO
字首命名。巨集語法通常應該是格式
(do-foo (variable the-foo-being-done return-value)
body...)
標準的例子: DOTIMES
, DOLIST
, DO-SYMBOLS
。
FOOCASE,EFOOCASE,CFOOCASE
與某些案例的輸入相匹配的巨集通常以 CASE
-postfix 命名。通常有一個 E...CASE
變數,如果輸入與任何情況不匹配則發出錯誤訊號,C...CASE
表示可持續錯誤。他們應該有類似的語法
(foocase input
(case-to-match-against (optionally-some-params-for-the-case)
case-body-forms...)
more-cases...
[(otherwise otherwise-body)])
標準示例: CASE
, TYPECASE
, HANDLER-CASE
。
例如,一個巨集將字串與正規表示式匹配,並將暫存器組繫結到變數。使用 CL-PPCRE 表示正規表示式。
(defmacro regexcase (input &body cases)
(let ((block-sym (gensym "block"))
(input-sym (gensym "input")))
`(let ((,input-sym ,input))
(block ,block-sym
,@(loop for (regex vars . body) in cases
if (eql regex 'otherwise)
collect `(return-from ,block-sym (progn ,vars ,@body))
else
collect `(cl-ppcre:register-groups-bind ,vars
(,regex ,input-sym)
(return-from ,block-sym
(progn ,@body))))))))
(defun test (input)
(regexcase input
("(\\d+)-(\\d+)" (foo bar)
(format t "Foo: ~a, Bar: ~a~%" foo bar))
("Foo: (\\w+)$" (foo)
(format t "Foo: ~a.~%" foo))
(otherwise (format t "Didn't match.~%"))))
(test "asd 23-234 qwe")
; Foo: 23, Bar: 234
(test "Foo: Foobar")
; Foo: Foobar.
(test "Foo: 43 - 23")
; Didn't match.
DEFINE-FOO,DEFFOO
定義事物的巨集通常用 DEFINE-
或 DEF
-prefix 命名。
標準的例子: DEFUN
, DEFMACRO
, DEFINE-CONDITION
。