How can I implement a push macro?

Can someone help me understand how pushit can be implemented as a macro? The lower version below evaluates the shape of the place twice and does this before evaluating the shape of the element:

(defmacro my-push (element place)
  `(setf ,place (cons ,element ,place)))

But if I try to fix this, as shown below, I'm setfin the wrong place:

(defmacro my-push (element place)
   (let ((el-sym    (gensym))
         (place-sym (gensym)))
     `(let ((,el-sym    ,element)
            (,place-sym ,place))
        (setf ,place-sym (cons ,el-sym ,place-sym)))))

CL-USER> (defparameter *list* '(0 1 2 3))
*LIST*
CL-USER> (my-push 'hi *list*)
(HI 0 1 2 3)
CL-USER> *list*
(0 1 2 3)

How can I setfindicate the right place without rating twice?

+2
source share
2 answers

Exercising this right seems a little more complicated. For example, the code for pushin SBCL 1.0.58:

(defmacro-mundanely push (obj place &environment env)
  #!+sb-doc
  "Takes an object and a location holding a list. Conses the object onto
  the list, returning the modified list. OBJ is evaluated before PLACE."
  (multiple-value-bind (dummies vals newval setter getter)
      (sb!xc:get-setf-expansion place env)
    (let ((g (gensym)))
      `(let* ((,g ,obj)
              ,@(mapcar #'list dummies vals)
              (,(car newval) (cons ,g ,getter))
              ,@(cdr newval))
         ,setter))))

Therefore, reading the documentation for get-setf-expand seems useful.

For writing, the generated code looks pretty nice:

:

(push 1 symbol)

(LET* ((#:G906 1) (#:NEW905 (CONS #:G906 SYMBOL)))
  (SETQ SYMBOL #:NEW905))

SETF ( , symbol ):

(push 1 (first symbol))

(LET* ((#:G909 1)
       (#:SYMBOL908 SYMBOL)
       (#:NEW907 (CONS #:G909 (FIRST #:SYMBOL908))))
  (SB-KERNEL:%RPLACA #:SYMBOL908 #:NEW907))

, setf, setf expansions , ( ). " " OnLisp.

: SBCL ( ), --fancy make.sh. / SBCL (, M-. Emacs + SLIME). , ( clean.sh install.sh, 90% ).

+3

, ( , SBCL) , :

* (macroexpand-1 '(push 1 *foo*))

(LET* ((#:G823 1) (#:NEW822 (CONS #:G823 *FOO*)))
  (SETQ *FOO* #:NEW822))
T

, , , , :

(defmacro my-push (element place)
   (let ((el-sym  (gensym))
         (new-sym (gensym "NEW")))
     `(let* ((,el-sym  ,element)
             (,new-sym (cons ,el-sym ,place)))
        (setq ,place ,new-sym)))))

:

  • setq setf. , ( , push ), .

  • , place ... , , element. , ? (, push , , / ... , .) -, " place", , ?

  • let* let ,el-sym ,new-sym. , cons, ,place ,element. , , , ?

  • , , setf , gensym.

, ... ( , .)

+1

Source: https://habr.com/ru/post/1543663/


All Articles