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

Popular posts from this blog

javascript - Karma not able to start PhantomJS on Windows - Error: spawn UNKNOWN -

c# - Display ASPX Popup control in RowDeleteing Event (ASPX Gridview) -

Nuget pack csproj using nuspec -