common lisp - define-modify-macro with operator argument -
in section 12.4 of on lisp, paul graham writes, "unfortunately, can't define correct _f
define-modify-macro
, because operator applied generalized variable given argument."
but what's wrong this?
(define-modify-macro _f (op operand) (lambda (x op operand) (funcall op x operand))) (let ((lst '(1 2 3))) (_f (second lst) #'* 6) lst) => (1 12 3)
has there perhaps been change made define-modify-macro in ansi common lisp wasn't valid @ time on lisp written? or there reasons other 1 stated not using define-modify-macro
here?
it appears graham want's able make call such as
(_f * (second lst) 6)
rather than
(_f #'* (second lst) 6)
but surely that's not in keeping lisp2 such common lisp?
according both lispworks's hyperspec , cltl2 (look define-modify-macro
), function assumed symbol (to function or macro). far know, following definition might not conforming specification:
(define-modify-macro _f (op operand) (lambda (x op operand) (funcall op x operand)))
but of course, possible implementation allows it. sure conforming standard, can define own function, or macro:
(defmacro funcall-1 (val fun &rest args) `(funcall ,fun ,val ,@args)) (define-modify-macro _ff (&rest args) funcall-1) (let ((x (list 1 2 3 4))) (_ff (third x) #'+ 10) x)
if wanted have function second argument, define macro:
(defmacro ff (fun-form place &rest args) `(_ff ,place ,fun-form ,@args))
basically, approach consists in wrapping funcall
in define-modify-macro
, , give desired function argument of function. @ first sight, looks hack, can see below, gives same macroexanded code 1 in on lisp, assuming modify latter little.
the macroexpansion of above is:
(let ((x (list 1 2 3 4))) (let* ((#:g1164 x) (#:g1165 (funcall #'+ (third #:g1164) 10))) (sb-kernel:%rplaca (cddr #:g1164) #:g1165)) x)
the version in on lisp behaves follows:
(defmacro _f (op place &rest args) (multiple-value-bind (vars forms var set access) (get-setf-expansion place) `(let* (,@(mapcar #'list vars forms) (, (car var) (,op ,access ,@args))) ,set))) (let ((x (list 1 2 3 4))) (_f * (third x) 10) x)
macroexpansion:
(let ((x (list 1 2 3 4))) (let* ((#:g1174 x) (#:g1175 (* (third #:g1174) 10))) (sb-kernel:%rplaca (cddr #:g1174) #:g1175)) x)
here, *
injected directly macroexpansion, means resulting code has no possible runtime overhead (though compilers handle (funcall #'+ ...)
equally well). if pass #'+
macro, fails macroexpand. major difference approach, not big limitation. in order allow on lisp version accept #'*
, or (create-closure)
operator, should modified follows:
(defmacro _f (op place &rest args) (multiple-value-bind (vars forms var set access) (get-setf-expansion place) `(let* (,@(mapcar #'list vars forms) (, (car var) (funcall ,op ,access ,@args))) ,set)))
(see call funcall
)
the previous example expanded follows, #'*
:
(let ((x (list 1 2 3 4))) (let* ((#:g1180 x) (#:g1181 (funcall #'* (third #:g1180) 10))) (sb-kernel:%rplaca (cddr #:g1180) #:g1181)) x)
now, version. on lisp uses _f
demonstrate how use get-setf-expansion
, , _f
example that. on other hand, implementation seems equally good.
Comments
Post a Comment