From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Pascal Bourguignon Newsgroups: gmane.emacs.help Subject: Re: Effective use of destructive functions Date: Thu, 12 Apr 2007 09:31:07 +0200 Organization: Informatimago Message-ID: <877isikq10.fsf@voyager.informatimago.com> References: <1176334962.373893.13990@w1g2000hsg.googlegroups.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1176363386 11581 80.91.229.12 (12 Apr 2007 07:36:26 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Thu, 12 Apr 2007 07:36:26 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Thu Apr 12 09:36:24 2007 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1Hbtqw-0004Mk-2u for geh-help-gnu-emacs@m.gmane.org; Thu, 12 Apr 2007 09:36:23 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Hbtv3-00040Y-6i for geh-help-gnu-emacs@m.gmane.org; Thu, 12 Apr 2007 03:40:37 -0400 Original-Path: shelby.stanford.edu!newshub.stanford.edu!news.tele.dk!news.tele.dk!small.news.tele.dk!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail Original-Newsgroups: gnu.emacs.help Original-Lines: 202 Original-X-Trace: individual.net 0QHfMxCuCw19Zhc1gfc3MAcQ+Yr9FSVnLcdw1W8PJqiOoSLKXk Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAABlBMVEUAAAD///+l2Z/dAAAA oElEQVR4nK3OsRHCMAwF0O8YQufUNIQRGIAja9CxSA55AxZgFO4coMgYrEDDQZWPIlNAjwq9 033pbOBPtbXuB6PKNBn5gZkhGa86Z4x2wE67O+06WxGD/HCOGR0deY3f9Ijwwt7rNGNf6Oac l/GuZTF1wFGKiYYHKSFAkjIo1b6sCYS1sVmFhhhahKQssRjRT90ITWUk6vvK3RsPGs+M1RuR mV+hO/VvFAAAAABJRU5ErkJggg== X-Accept-Language: fr, es, en X-Disabled: X-No-Archive: no User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.94 (gnu/linux) Cancel-Lock: sha1:+bJvr/xq3A9IIUppPqJyucEXu1A= Original-Xref: shelby.stanford.edu gnu.emacs.help:146999 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:42603 Archived-At: "achambers.home@googlemail.com" writes: > Here's some code.... > > (setq doc '(root (child 1 2) (child 3 4))) If you plan to modify these conses, you shouldn't let the reader create them with quote. Explicitely build these lists! (setq doc (list 'root (list 'child 1 2) (list 'child 3 4))) > (setq editable-child (car (cdr doc))) > ;; (setq editable-child (mapcan (lambda (x) > ;; (cons x nil)) editable-child)) > > (setcdr editable-child '(10 11)) Same with this one, if you plan to do a (setcar (cdr editable-child) 12), use list: (setcdr editable-child (list 10 11)) > editable-child > doc > > It seems that in the commented sexp, altering the symbol > editable-child using setcdr has no effect on doc because the contents > of editable-child is a copy of the contents of doc rather than a > direct reference to a particular `place' in doc. > > This is a stripped down version of my real problem which is to > creating a number of widgets out of the data in doc. I want to make > a :notify function for each widget that updates doc when an element of > the tree is edited. > > My question is...How can you run the contents of editable-child > through a mapping function, and keep the structure so that any changes > to the return value carry on up to doc? Indeed, mapcar builds a new list with the results of the function. (let* ((a (list 1 2 3)) (b (mapcar (lambda (x) (* 2 x)) a))) (list a b)) --> ((1 2 3) (2 4 6)) You wouldn't want to modify the list a when you build the list b... In your case, you can modify each element of your list, without touching the cdr of the cons cells of the list, by using map-into. So instead of writing (setq editable-child (mapcan (lambda (x) (cons x nil)) editable-child)) you'd write: doc --> (root (child 1 2) (child 3 4)) editable-child --> (child 1 2) (map-into editable-child (function list) editable-child) --> ((child) (1) (2)) doc --> (root ((child) (1) (2)) (child 3 4)) editable-child --> ((child) (1) (2)) Well, it's not in emacs AFAIK, so here is an emacs-cl implementation of map-into; see http://www.lispworks.com/documentation/HyperSpec/Body/f_map_in.htm for the specifications. (require 'cl) (require 'eieio) (defclass iterator () ()) (defclass iterator-list (iterator) ((head :initarg :sequence :type list))) (defclass iterator-vector (iterator) ((vector :initarg :sequence :type VECTOR) (index :initform 0))) (defmethod end-of-sequence-p ((self iterator-list)) (null (slot-value self 'head))) (defmethod end-of-sequence-p ((self iterator-vector)) (>= (slot-value self 'index) (length (slot-value self 'vector)))) (defmethod current-item ((self iterator-list)) (car (slot-value self 'head))) (defmethod current-item ((self iterator-vector)) (aref (slot-value self 'vector) (slot-value self 'index))) (defmethod set-current-item ((self iterator-list) value) (setf (car (slot-value self 'head)) value)) (defmethod set-current-item ((self iterator-vector) value) (setf (aref (slot-value self 'vector) (slot-value self 'index)) value)) (defmethod advance ((self iterator-list)) (setf (slot-value self 'head) (cdr (slot-value self 'head)))) (defmethod advance ((self iterator-vector)) (incf (slot-value self 'index))) (defun map-into (result-sequence function &rest sequences) (cond ((every (function listp) sequences) (cond ((listp result-sequence) (do ((sequences sequences (mapcar (function cdr) sequences)) (target result-sequence (cdr target))) ((or (null target) (some (function null) sequences)) result-sequence) (setf (car target) (apply function (mapcar (function car) sequences))))) ((vectorp* result-sequence) (do ((sequences sequences (mapcar (function cdr) sequences)) (target 0 (1+ target))) ((or (>= target (length result-sequence)) (some (function null) sequences)) result-sequence) (setf (aref result-sequence target) (apply function (mapcar (function car) sequences))))) (t (error "RESULT-SEQUENCE is neither a LIST or a VECTOR.")))) ((every (function vectorp*) sequences) (cond ((listp result-sequence) (do ((source 0 (1+ source)) (min (apply (function min) (mapcar (function length) sequences))) (target result-sequence (cdr target))) ((or (null target) (>= source min)) result-sequence) (setf (car target) (apply function (mapcar (lambda (seq) (aref seq source)) sequences))))) ((vectorp* result-sequence) (do ((index 0 (1+ index)) (min (apply (function min) (length result-sequence) (mapcar (function length) sequences)))) ((>= index min) result-sequence) (setf (aref result-sequence index) (apply function (mapcar (lambda (seq) (aref seq index)) sequences))))) (t (error "RESULT-SEQUENCE is neither a LIST or a VECTOR.")))) (t (do ((res (make-instance (cond ((listp result-sequence) 'iterator-list) ((vectorp* result-sequence) 'iterator-vector) (t (error "RESULT-SEQUENCE is neither a LIST or a VECTOR."))) :sequence result-sequence)) (sequences (mapcar (lambda (seq) (make-instance (cond ((listp seq) 'iterator-list) ((vectorp* seq) 'iterator-vector) (t (error "A SEQUENCE is neither a LIST or a VECTOR."))) :sequence seq)) sequences))) ((some (function end-of-sequence-p) (cons res sequences)) result-sequence) (set-current-item res (apply function (mapcar (function current-item) sequences))) (dolist (seq (cons res sequences)) (advance seq)))))) (let ((result (make-list 10 0))) (print (map-into result (function +) '(1 2 3 4 5 6) '(100 200 300 400 500 600 700 800))) (print (map-into result (function *) result '(2 2 2 3 3 3))) (map-into result (lambda (x) (+ 1000 x)) result)) (101 202 303 404 505 606 0 0 0 0) (202 404 606 1212 1515 1818 0 0 0 0) (1202 1404 1606 2212 2515 2818 1000 1000 1000 1000) -- __Pascal Bourguignon__ http://www.informatimago.com http://pjb.ogamita.org