这是一个很好的用例(在 Lisp 中,what is to append as push is to cons?define-modify-macro
中也有描述,但目前的情况更简单)。首先,将有界总和写成一个函数。这很简单;如果它们的总和大于,则返回and ,否则返回。根据您发布的伪代码和 Lisp 代码,这可能是:val
delta
1.0
1.0
(defun sum-bounded (val delta)
(if (>= (+ val delta) 1.0)
1.0
(+ val delta)))
实际上,仅计算此值,您可以使用:
(defun sum-bounded (val delta)
(min 1.0 (+ val delta)))
现在你define-modify-macro
用来定义一个宏incf-bounded
:
(define-modify-macro incf-bounded (delta) sum-bounded)
宏将一个位置作为它的第一个参数,将 delta 作为第二个参数。它安全地从 place 检索值,sum-bounded
使用该值和 delta 进行计算,然后将结果存储回place。这里的“安全”意味着它避免了多重评估可能出现的问题,正如Lars Brinkhoff 明智地警告的那样。然后你只需使用它:
(let ((x .5))
(incf-bounded x .3)
(print x) ; prints 0.8
(incf-bounded x .3)
(print x)) ; prints 1.0 (not 1.1)
对于更复杂的情况,要修改的地方自然不是您想要的宏的第一个参数,您需要编写自己的宏并使用get-setf-expansion
,但这在中进行了更详细的解释
一起编码以便于复制和粘贴
(defun sum-bounded (val delta)
"Returns the lesser of 1.0 or the sum of val and delta."
(min 1.0 (+ val delta)))
(define-modify-macro incf-bounded (delta) sum-bounded
"(incf-bounded place delta) computes the sum of the value of the
place and delta, and assigns the lesser of 1.0 and the sum of the value
and delta to place.")
(defun demo ()
(let ((x .5))
(incf-bounded x .3)
(print x) ; prints 0.8
(incf-bounded x .3)
(print x))) ; prints 1.0 (not 1.1)