Macros 编写破坏性宏或函数(如incf)?

Macros 编写破坏性宏或函数(如incf)?,macros,lisp,common-lisp,Macros,Lisp,Common Lisp,我需要一个incf函数,它在增量期间执行一些边界检查: val := val + delta if val >= 1.0 then return 1.0 else return val 我可以使用incf编写此代码: (defun incf-bounded(val delta) (incf val delta) (if (>= val 1.0) 1.0 val)) 在这种情况下,我需要像这样使用(setf x(incf-bounded x delta)

我需要一个
incf
函数,它在增量期间执行一些边界检查:

val := val + delta
if val >= 1.0
   then return 1.0
   else return val
我可以使用
incf
编写此代码:

(defun incf-bounded(val delta)
  (incf val delta)
  (if (>= val 1.0) 1.0 val))    

在这种情况下,我需要像这样使用
(setf x(incf-bounded x delta))
。但是我如何编写一个我可以使用的,比如
(incf-bounded x delta)
,也就是说,
x
将被修改的地方?

如果你想让它成为一个有副作用的地方,你可能需要小心
val

(defmacro incf-bounded(形式为增量和环境环境)
(多值绑定(temps-vals-vars-writer-reader)
(获取setf扩展表单env)
`(让*(,@(地图车)列出临时值)
(,(第一个变量)(min(+,delta,reader)1.0));已编辑,请参见注释。
(作者)
试试看

(let((list(list 0.5 1)))
(循环i=-1重复3次do(增量有界(第n(增量i)列表)0.5))
(列表)

(这看起来不必要的复杂,因为我希望在
incf-bounded
的第一个参数中有一个副作用)

这是一个很好的用例(在中也有描述,但现在的情况更简单)。首先,将有界和写成函数。这很简单;它接受
val
delta
,如果它们的总和大于
1.0
,则返回
1.0
,否则返回它们的总和。根据您发布的伪代码和Lisp代码,这可能是:

(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)
宏的第一个参数为place,第二个参数为delta。它安全地从该位置检索值,用该值和增量计算
有界和
,然后将结果存储回该位置。这里的“安全”意味着它避免了多次评估可能出现的问题。那你就用它吧:

(let ((x .5))
  (incf-bounded x .3)
  (print x)                             ; prints 0.8
  (incf-bounded x .3)
  (print x))                            ; prints 1.0 (not 1.1)
对于更复杂的情况,如果要修改的位置自然不是所需宏的第一个参数,则需要编写自己的宏并使用它,但在中有更详细的说明

全部编码,便于复制和粘贴
这可能是的重复,已被接受的答案解释了
define modify macro
的用法,这是您可能希望在此处使用的。您编写的lisp代码与伪代码不匹配。
else
行不应该是
else val:=val+delta
?可能重复不必要的复杂,为什么不直接使用
define modify宏
,它为您处理
get setf扩展
(无耻插头:我举了一个例子。)是的,那很方便。我自己很喜欢使用
get setf expension
。要正确工作,
(+,reader,delta)
表单应该是
(+,delta,reader)
(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)