ram*_*rur 3 lisp macros common-lisp
我需要一个incf在增量期间执行某些边界检查的函数:
val := val + delta
if val >= 1.0
then return 1.0
else return val
Run Code Online (Sandbox Code Playgroud)
我可以这样写incf:
(defun incf-bounded(val delta)
(incf val delta)
(if (>= val 1.0) 1.0 val))
Run Code Online (Sandbox Code Playgroud)
在这种情况下我需要使用它(setf x (incf-bounded x delta)).但是我该怎么写一个我可以使用的(incf-bounded x delta),比如,哪里x会被修改?
这是一个很好的用例define-modify-macro(在Lisp中,它也被描述为什么是push to cons,但是本例更简单).首先,将有界和作为函数编写.这非常简单; 它需要val和delta并返回1.0,如果它们的总和大于1.0,并且它们的和其他.根据您发布的伪代码和Lisp代码,这可能是:
(defun sum-bounded (val delta)
(if (>= (+ val delta) 1.0)
1.0
(+ val delta)))
Run Code Online (Sandbox Code Playgroud)
实际上,只需计算此值,您就可以使用:
(defun sum-bounded (val delta)
(min 1.0 (+ val delta)))
Run Code Online (Sandbox Code Playgroud)
现在您define-modify-macro用来定义一个宏incf-bounded:
(define-modify-macro incf-bounded (delta) sum-bounded)
Run Code Online (Sandbox Code Playgroud)
宏需要的地方作为第一个参数和delta作为第二.它安全地从该位置检索值,sum-bounded使用该值和delta 计算,然后将结果存储回该位置."安全"在这里意味着它避免了多重评估可能出现的问题,正如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)
Run Code Online (Sandbox Code Playgroud)
对于更复杂的情况下发生,将被修改不自然的第一个参数是你想要的宏,你需要编写自己的宏和使用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)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
390 次 |
| 最近记录: |