编写破坏性宏或类似incf的函数

编写破坏性宏或类似incf的函数

本文介绍了编写破坏性宏或类似incf的函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个incf函数,该函数会在增量过程中进行一些边界检查:

I need an incf function which does some bounds checking during the increment:

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将在哪里修改?

In such case I need to use this like (setf x (incf-bounded x delta)). But how do I write one which I can use like (incf-bounded x delta), i.e., where x will be modified?

推荐答案

这是 define-modify-macro (也已对此进行了描述在Lisp中添加作为推送是不利因素吗?,但目前的情况较为简单).首先,将有界和写为一个函数.这很简单;如果valdelta的总和大于1.0,则返回1.0,否则返回.根据您发布的伪代码和Lisp代码,可能是:

This is a good use case for define-modify-macro (which has also been described in what is to append as push is to cons, in Lisp?, but the present case is simpler). First, write your bounded sum as a function. This is pretty straightforward; it takes val and delta and returns 1.0 if their sum is greater than 1.0, and their sum otherwise. Based on the pseudo code and Lisp code you posted, this could be:

(defun sum-bounded (val delta)
  (if (>= (+ val delta) 1.0)
      1.0
      (+ val delta)))

实际上,仅对于计算此值,您可以使用:

Actually, for just computing this value, you can use:

(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作为第二个参数.它安全地从该位置检索值,使用该值和增量计算sum-bounded,然后将结果存储回 place . 安全"是指它避免了多次评估的可能问题,如 Lars Brinkhoff明智地警告.然后,您只需使用它即可:

The macro takes a place as its first argument and delta as a second. It safely retrieves the value from the place, computes sum-bounded with that value and delta, and then stores the result back into the place. "Safely" here means that it avoids possible problems with multiple evaluation, as Lars Brinkhoff's wisely warns against. Then you just use it:

(let ((x .5))
  (incf-bounded x .3)
  (print x)                             ; prints 0.8
  (incf-bounded x .3)
  (print x))                            ; prints 1.0 (not 1.1)

在更复杂的情况下,要修改的 place 自然不是您想要的宏的第一个参数,您需要编写自己的宏并使用 get-setf-expansion ,但这在

For more complicated cases where the place that would be modified isn't naturally the first argument to the macro that you want, you'd need to write your own macro and use get-setf-expansion, but this is explained in more detail in

(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)

这篇关于编写破坏性宏或类似incf的函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-18 10:11