What should the definition of SET-FROM-LIST be if I want the
following behaviour:
(let ((foo (list 1 2 3)) bar baz bat)
(set-from-list foo bar baz bat)
(values bar baz bat))
==> 1; 2; 3
This works:
(defmacro set-from-list (list &rest vars)
`(eval `(setf ,@(mapcan (lambda (x) (list x (pop ,list))) ',vars))))
but I have a strong feeling there's a more elegant way to do this.
Any ideas? (The list can be used up or left as is, doesn't matter.)
--
Ola Rinta-Koski ···@cyberell.com
Cyberell Oy +358 41 467 2502
Rauhankatu 8 C, FIN-00170 Helsinki, FINLAND www.cyberell.com
Ola Rinta-Koski <···@cyberell.com> writes:
> What should the definition of SET-FROM-LIST be if I want the
> following behaviour:
>
> (let ((foo (list 1 2 3)) bar baz bat)
> (set-from-list foo bar baz bat)
> (values bar baz bat))
> ==> 1; 2; 3
>
> This works:
>
> (defmacro set-from-list (list &rest vars)
> `(eval `(setf ,@(mapcan (lambda (x) (list x (pop ,list))) ',vars))))
>
> but I have a strong feeling there's a more elegant way to do this.
> Any ideas? (The list can be used up or left as is, doesn't matter.)
> --
> Ola Rinta-Koski ···@cyberell.com
> Cyberell Oy +358 41 467 2502
> Rauhankatu 8 C, FIN-00170 Helsinki, FINLAND www.cyberell.com
There has been a thread about exactly this problem (with reversed
argument order) lately. It can be found at
<http://groups.google.com/groups?hl=en&threadm=m3n137u8lu.fsf%40bird.agharta.de>
As I was the original poster, I have assembled a list of all proposals
that came in during this thread. See below.
HTH,
Edi.
;;; my (Edi Weitz <···@agharta.de>) first solution
;;; posted to comp.lang.lisp on October 4, 2001, as
;;; <···················@bird.agharta.de>
;; doesn't work correctly because EVAL works
;; in a null lexical environment and thus
;; this macro can't be placed inside of a LET form
(defmacro set-from-list (places-list value-list)
`(progn
,@(mapcar #'(lambda (place value)
`(setf ,place ,value))
places-list (eval value-list))))
;;; solution by Dr. Shlomo Argamon <·······@sunlightNOSPAM.cs.biu.ac.il>
;;; posted to comp.lang.lisp on October 4, 2001, as
;;; <····················@sunlight.i-have-a-misconfigured-system-so-shoot-me>
;; won't work with places, just with symbols.
;; also doesn't work inside of LET forms because
;; SET assigns the SYMBOL-VALUE not the lexical value.
(defmacro set-from-list (places-list value-list)
(let ((var (gensym)))
`(let ((,var ,value-list))
(mapcar #'(lambda (place value)
(set place value))
(quote ,places-list) ,var))))
;;; solution by Kalle Olavi Niemitalo <···@iki.fi>
;;; posted to comp.lang.lisp on October 4, 2001, as
;;; <····················@stekt34.oulu.fi>
(defmacro set-from-list (places values-form)
(let ((=values= (gensym)))
`(let ((,=values= ,values-form))
,@(loop for place in places
collect `(setf ,place (pop ,=values=))))))
;;; solution by Paul Foley
;;; sent to me by private email on October 4, 2001
(defmacro set-from-list (places-list values-list)
`(mapc #'funcall (list ,@(mapcar (lambda (place)
`(lambda (value) (setf ,place value)))
places-list))
,values-list))
;;; solution by Kent M Pitman <······@world.std.com>
;;; posted to comp.lang.lisp on October 4, 2001, as
;;; <····················@world.std.com>
(defmacro set-from-list (places-list value-list)
(let ((temps (mapcar #'(lambda (place)
(declare (ignore place))
(gensym))
places-list)))
`(destructuring-bind ,temps ,value-list
(setf ,@(mapcan #'list places-list temps)))))
;;; Christopher Vogt <····@computer.org>
;;; suggested to look at PROGV in an article
;;; posted to comp.lang.lisp on October 4, 2001, as
;;; <······················@computer.org>
;;; solution by Kent M Pitman <······@world.std.com>
;;; posted to comp.lang.lisp on October 4, 2001, as
;;; <····················@world.std.com>
(defmacro set-from-list (places-list value-list)
(let ((temps (mapcar #'(lambda (place)
(declare (ignore place))
(gensym))
places-list)))
`(destructuring-bind ,temps ,value-list
(setf ,@(mapcan #'list places-list temps)))))
;;; solution by Kaz Kylheku <···@ashi.footprints.net>
;;; posted to comp.lang.lisp on October 5, 2001, as
;;; <···························@news1.rdc1.bc.home.com>
(defmacro set-from-list (places-list value-list)
(if (and (listp value-list) (eq (first value-list) 'quote))
`(setf ,@(mapcan #'(lambda (place value)
`(,place ',value)) places-list (second value-list)))
(let ((iterator (gensym)))
`(let ((,iterator ,value-list))
,@(mapcan #'(lambda (place)
`((setf ,place (car ,iterator))
(setf ,iterator (cdr ,iterator))))
places-list)))))
;;; solution by Sam Steingold <···@gnu.org>
;;; posted to comp.lang.lisp on October 5, 2001, as
;;; <··················@xchange.com>
(defmacro set-from-list (places values)
(let ((gens (mapcar (lambda (x) (declare (ignore x)) (gensym)) places)))
`(destructuring-bind ,gens ,values
(setf ,@(mapcan #'list places gens)))))
;;; Kalle Olavi Niemitalo <···@iki.fi> observed that none
;;; of the solutions above preserves the standard left-to-right
;;; evaluation order and provided a counter-example
;;; posted to comp.lang.lisp on October 4, 2001, as
;;; <···················@Astalo.y2000.kon.iki.fi>
;; all solutions following below try to overcome this problem
(let ((x '()))
(set-from-list ((cdr (push 42 x))) (copy-list x))
;; which means: (setf (cdr (push 42 x)) (first x))
x) ; should be (42 . 42)
;;; solution by Kent M Pitman <······@world.std.com>
;;; posted to comp.lang.lisp on October 5, 2001, as
;;; <····················@world.std.com>
(defmacro set-from-list (places values)
(let ((expansion-data-list (mapcar #'(lambda (place)
(multiple-value-list
(get-setf-expansion place)))
places)))
`(let ,(mapcan #'(lambda (expansion-data)
(mapcar #'list
(first expansion-data)
(second expansion-data)))
expansion-data-list)
(destructuring-bind ,(mapcar #'(lambda (place expansion-data)
(let ((vars (third expansion-data)))
(unless (= (length vars) 1)
(error "Can't SET-FROM-LIST ~S."
place))
(first vars)))
places expansion-data-list)
,values
,@(mapcar #'fourth expansion-data-list)))))
;;; my (Edi Weitz <···@agharta.de>) next trial
;;; posted to comp.lang.lisp on October 5, 2001, as
;;; <···················@bird.agharta.de>
(defmacro set-from-list (places values)
(let ((=list-val= (gensym)))
(let (vars forms var set access)
(loop for place in places
do (multiple-value-setq (vars forms var set access)
(get-setf-method place))
append (mapcar #'list vars forms) into place-bindings
collect `(,(car var) (pop ,=list-val=)) into temp-bindings
collect set into assignments
finally (progn
(return `(let* ,place-bindings
(let ((,=list-val= ,values))
(let* ,temp-bindings
,@assignments)))))))))
;;; another version of mine,
;;; also from <···················@bird.agharta.de>
;; tries to behave reasonably if PLACES and VALUES
;; have different length
(defmacro set-from-list (places values
&key
(fill-form nil supplied-fill-form-p))
(let ((=list-val= (gensym))
(=list-len= (gensym))
(=excess-len= (gensym)))
(let (vars forms var set access)
(loop for place in places
do (multiple-value-setq (vars forms var set access)
(get-setf-method place))
append (mapcar #'list vars forms) into place-bindings
collect `(,(car var) (pop ,=list-val=)) into temp-bindings
collect `(when (>= (decf ,=list-len=) 0) ,set)
into assignments
finally (progn
(return `(let* ,(append place-bindings
`((,=list-val= ,values)
(,=list-len=
(length ,=list-val=))))
,(if supplied-fill-form-p
`(let ((,=excess-len=
(- ,(length places)
,=list-len=)))
(when (> ,=excess-len= 0)
(setq ,=list-val=
(nconc ,=list-val=
(make-list
,=excess-len=
:initial-element
,fill-form)))
(incf ,=list-len=
,=excess-len=))))
(let* ,temp-bindings
,@assignments)
,=list-val=)))))))
;;; another solution by Kent M Pitman <······@world.std.com>
;;; posted to comp.lang.lisp on October 5, 2001, as
;;; <····················@world.std.com>
;; may be affected by MULTIPLE-VALUES-LIMIT
(defmacro set-from-list (places values)
(let ((temps (mapcar #'(lambda (x) (declare (ignore x)) (gensym)) places)))
;; KLUDGE ALERTS:
;; (1) Tricks MULTIPLE-VALUE-SETQ into being MULTIPLE-VALUE-SETF
;; (2) Makes use of its special knowledge that each place will be used
;; only once and in the right order, so intermediate temps are not
;; needed explicitly to preserve left-to-right order nor single
;; in the symbol-macrolet expansion. (MULTIPLE-VALUE-SETQ has a
;; similar issue to solve again for itself which has to be solved
;; differently.)
`(symbol-macrolet ,(mapcar #'list temps places)
(multiple-value-setq ,temps (values-list ,values)))))
;;; solution by Tim Moore <·····@bricoworks.com>
;;; posted to comp.lang.lisp on October 5, 2001, as
;;; <·················@216.39.145.192>
;; may also be affected by MULTIPLE-VALUES-LIMIT
;; but is otherwise the coolest solution IMHO
(defmacro set-from-list (places values)
`(setf (values ,@places) (values-list ,values)))
···@agharta.de (Dr. Edmund Weitz) writes:
> Ola Rinta-Koski <···@cyberell.com> writes:
> > What should the definition of SET-FROM-LIST be if I want the
> > following behaviour:
> >
> > (let ((foo (list 1 2 3)) bar baz bat)
> > (set-from-list foo bar baz bat)
> > (values bar baz bat))
> > ==> 1; 2; 3
> There has been a thread about exactly this problem (with reversed
> argument order) lately.
Thanks a lot. I decided to use this one:
> ;;; solution by Tim Moore <·····@bricoworks.com>
> ;;; posted to comp.lang.lisp on October 5, 2001, as
> ;;; <·················@216.39.145.192>
> ;; may also be affected by MULTIPLE-VALUES-LIMIT
> ;; but is otherwise the coolest solution IMHO
> (defmacro set-from-list (places values)
> `(setf (values ,@places) (values-list ,values)))
--
Ola Rinta-Koski ···@cyberell.com
Cyberell Oy +358 41 467 2502
Rauhankatu 8 C, FIN-00170 Helsinki, FINLAND www.cyberell.com
In article <··············@arenal.cyberell.com>, Ola Rinta-Koski <···@cyberell.com> wrote:
> > > What should the definition of SET-FROM-LIST be if I want the
> > > following behaviour:
> > >
> > > (let ((foo (list 1 2 3)) bar baz bat)
> > > (set-from-list foo bar baz bat)
> > > (values bar baz bat))
> > > ==> 1; 2; 3
>
> > There has been a thread about exactly this problem (with reversed
> > argument order) lately.
>
> Thanks a lot. I decided to use this one:
>
> > ;;; solution by Tim Moore <·····@bricoworks.com>
> > ;;; posted to comp.lang.lisp on October 5, 2001, as
> > ;;; <·················@216.39.145.192>
> > ;; may also be affected by MULTIPLE-VALUES-LIMIT
> > ;; but is otherwise the coolest solution IMHO
> > (defmacro set-from-list (places values)
> > `(setf (values ,@places) (values-list ,values)))
I'm not sure how you're going to use the macro, but if you use it
where destruturing-bind would suffice, e.g:
(destructuring-bind (bar baz bat)
(list 1 2 3)
...
)
I would hate that.
abe
--
<keke at mac com>
····@ma.ccom (Takehiko Abe) writes:
> In article <··············@arenal.cyberell.com>, Ola Rinta-Koski <···@cyberell.com> wrote:
> > > > (let ((foo (list 1 2 3)) bar baz bat)
> > > > (set-from-list foo bar baz bat)
> > > > (values bar baz bat))
> > > > ==> 1; 2; 3
> I'm not sure how you're going to use the macro, but if you use it
> where destruturing-bind would suffice, e.g:
>
> (destructuring-bind (bar baz bat)
> (list 1 2 3)
> ...
> )
>
> I would hate that.
No need to worry, I won't. The variables are already bound with a LET
since I'm not doing the SET-FROM-LIST in all cases.
--
Ola Rinta-Koski ···@cyberell.com
Cyberell Oy +358 41 467 2502
Rauhankatu 8 C, FIN-00170 Helsinki, FINLAND www.cyberell.com