From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Eric Abrahamsen Newsgroups: gmane.emacs.devel Subject: Help with recursive destructive function Date: Fri, 04 May 2018 18:04:57 -0700 Message-ID: <87efiqzzd2.fsf@ericabrahamsen.net> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1525482360 15733 195.159.176.226 (5 May 2018 01:06:00 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sat, 5 May 2018 01:06:00 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat May 05 03:05:56 2018 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1fEle5-0003w0-AE for ged-emacs-devel@m.gmane.org; Sat, 05 May 2018 03:05:53 +0200 Original-Received: from localhost ([::1]:36988 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fElgA-0004D2-DX for ged-emacs-devel@m.gmane.org; Fri, 04 May 2018 21:08:02 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:35820) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fElg3-0004Ct-NR for emacs-devel@gnu.org; Fri, 04 May 2018 21:07:56 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fElg0-0005L2-IM for emacs-devel@gnu.org; Fri, 04 May 2018 21:07:55 -0400 Original-Received: from [195.159.176.226] (port=52063 helo=blaine.gmane.org) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fElg0-0005Im-At for emacs-devel@gnu.org; Fri, 04 May 2018 21:07:52 -0400 Original-Received: from list by blaine.gmane.org with local (Exim 4.84_2) (envelope-from ) id 1fEldl-0003f3-Tp for emacs-devel@gnu.org; Sat, 05 May 2018 03:05:33 +0200 X-Injected-Via-Gmane: http://gmane.org/ Original-Lines: 55 Original-X-Complaints-To: usenet@blaine.gmane.org Cancel-Lock: sha1:gFQsMqKwOiwyzTmAF4E1yqr10po= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 195.159.176.226 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:225061 Archived-At: So I'm revisiting my nemesis, eieio-persistent, and trying to write a function for serializing data to disk in a generalized, data-agnostic way. The function needs to take a totally arbitrary list of data, and run a function over it so that each element in the (possibly very nested) list is tested and, if the test is positive, destructively replaced by a new value. I'd like to make it destructive because there could potentially be a very large amount of data, and very few of the elements will actually need to be altered, and I'm afraid copying enormous structures will be slow. I'm pretending that the job is to walk an arbitrary tree, and upcase any and all strings in that tree. That's not the job, but I'm confident that if I can make this work, it will be relatively simple to translate into the actual job. (It will also have to handle hash-tables and vectors, again I think that's all relatively straightforward.) So here's my test data: (setq test-data '("a" 1 "b" ("c" (2 ("d" . 3)) (4 . "e") "f"))) And the result I want (the destructive alteration of `test-data') is: ("A" 1 "B" ("C" (2 ("D" . 3)) (4 . "E") "F")) The function I came up with always operates at one higher level of nesting, because that's the only way to get a setf-able handle to internal elements of the data structure: if you `mapc' a function over a list, you can't use the resulting lambda argument symbol to set anything. So I stay a level "up", in order to use setf, setcar, setcdr, etc. I did briefly consider `cl-symbol-macrolet', since it seems to be made to address these sorts of problems, but this other solution more or less came clear before I got a clear mental grasp of symbol-macrolet. I'm hoping that someone might be willing to lend me some brain, and tell me if I've done something conceptually wrong. Will this function do what I expect it to do? (defun walk (thing) (cond ((listp (cdr thing)) (dotimes (i (length thing)) (cond ((stringp (nth i thing)) (setf (nth i thing) (upcase (nth i thing)))) ((listp (nth i thing)) (walk (nth i thing)))))) ((consp thing) (when (stringp (car thing)) (setcar thing (upcase (car thing)))) (when (stringp (cdr thing)) (setcdr thing (upcase (cdr thing)))))))