This is a good use case for define-modify-macro (which has also been described in what you need to add as push to minus in Lisp?, But this case is simpler). First write your limited amount as a function. It is pretty simple; it takes val and delta and returns 1.0 if their sum is greater than 1.0 , and their sum otherwise. Based on the pseudocode and Lisp code you posted, it could be:
(defun sum-bounded (val delta) (if (>= (+ val delta) 1.0) 1.0 (+ val delta)))
Actually, for a simple calculation of this value, you can use:
(defun sum-bounded (val delta) (min 1.0 (+ val delta)))
Now you use define-modify-macro to define the incf-bounded macro:
(define-modify-macro incf-bounded (delta) sum-bounded)
The macro takes place as the first argument and delta as the second. It safely retrieves the value from the location, computes the sum-bounded with that value and the delta, and then saves the result back to the location. โSafeโ means that this avoids the potential for multiple rating problems, as Lars Brinkhoff 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)
In more complex cases where the place to be changed is not the natural first argument for the macro you want, you need to write your own macro and use get-setf-expansion , but this is described in more detail in
- what needs to be added as push to minus in Lisp?
Code to simplify copying and pasting
(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)
Joshua taylor
source share