Reputation: 1941
For rapid prototyping purposes in common-lisp it would be convenient to be able to easily function-modify an object in an arbitrary data structure. This would seem to involve calling an arbitrary function on a place in the data structure, replacing the object at that place with the result of the function call. Common-lisp has a number of specialized modification macros (eg, incf
, push
, getf
, etc) for particular types of objects, and setf
for generalized place modification (eg, setf-second
, setf-aref
, setf-gethash
, etc). But rather than inventing new specialized macros for other object types, or having to mentally consider the characteristics of each macro (slowing down development), it might be nice to have a generalized setf-like modification capability that was simpler to use than setf
. For example, instead of (setf (second (getf plist indicator)) (1+ (second (getf plist indicator))))
or (incf (second (getf plist indicator)))
, one might write (callf (second (getf plist indicator)) #'1+)
, using any of the normal one argument functions (or lambda-expression) provided by common-lisp or the user. Here is an attempt at code:
(defun call (object function) (funcall function object))
(define-modify-macro callf (&rest args) call)
Will something like this work for all general cases, and can it actually simplify code in practice?
Upvotes: 1
Views: 104
Reputation: 60004
callf
I think what you are looking for is _f
from OnLisp 12.4:
(defmacro _f (op place &rest args)
"Modify place using `op`, e.g., (incf a) == (_f a 1+)"
(multiple-value-bind (vars forms var set access)
(get-setf-expansion place)
`(let* (,@(mapcar #'list vars forms)
(,(car var) (,op ,access ,@args)))
,set)))
This uses get-setf-expansion
- the workhorse of generalized reference handling.
Note that _f
only works with single-value places.
IOW, (_f (values a b c) 1+)
will not increment all 3 variables.
It is not all that hard to fix that though...
This really depends on your coding style and the specific problem you are solving.
Upvotes: 2