emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Help with recursive destructive function


From: Eric Abrahamsen
Subject: Re: Help with recursive destructive function
Date: Sat, 28 Jul 2018 13:52:40 -0700
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

On 05/15/18 01:16 AM, Michael Heerdegen wrote:
> Eric Abrahamsen <address@hidden> writes:
>
>> For backwards compatibility, we need to be able to handle lists that are
>> quoted, or that start with the symbol `list'. This will sound familiar
>> to you... In the non-destructive version, it was easy enough just to
>> return (cdr thing) instead of thing.
>
> What will this code do when the saved list was really quoted, or was a
> list with the symbol list as first element?  Wouldn't the backward
> compatible version cause errors?

After weeks of avoiding this, I'm nearly there. This version does
everything I need it to, EXCEPT I have somehow lost the ability to
handle single-atom data, which was the whole point of passing in a
gv-ref. I don't understand why, it seemed to be working fine, but I
switched to cl-labels and maybe changed some other things (I didn't keep
the intermediate version), and now it just doesn't do it. Would you help
me take one more look at this?

It also doesn't handle '(list), but those cases are rare and occur at
top-level, so I can take care of them in pre-processing.

#+BEGIN_SRC elisp

(defun deep-edit (data edit-p traverse-p)
  (let ((stack (list (gv-deref data))))
    (cl-labels ((handle-refs
                 (refs)
                 (dolist (ref refs)
                   (let* ((val (gv-deref ref))
                          (edit (when val (funcall edit-p val))))
                     (when (car edit)
                       (cl-callf (lambda (x) (funcall (car edit) x))
                           (gv-deref ref))
                       (when (cdr edit)
                         (handle-refs (list ref))))
                     (when (funcall traverse-p (gv-deref ref))
                       (push (gv-deref ref) stack))))))
      (while stack
        (let ((current (pop stack)))
          (cond
           ((consp current)
            (handle-refs `(,(gv-ref (car current))
                           ,(gv-ref (cdr current)))))
           ((and (arrayp current) (not (stringp current)))
            (handle-refs
             (mapcar (lambda (idx) (gv-ref (aref current idx)))
                     (number-sequence 0 (1- (length current))))))
           ((hash-table-p current)
            (let ((refs '()))
              (maphash (lambda (key _val)
                         ;; Order matters here!
                         (push (gv-ref (gethash key current)) refs)
                         (push (gv-ref (deep-edit-hash-key key current))
                               refs))
                       current)
              (handle-refs (nreverse refs))))))))))

(let ((tree '("one" two ''(three "four" (list "five")))))
 (deep-edit
  (gv-ref tree)
  (lambda (thing)
    (cond ((consp thing)
           (pcase (car thing)
             ('list (cons #'cdr t))
             ('quote (cons #'cadr t))))
          ((stringp thing)
           (cons #'upcase nil))))
  (lambda (thing)
    (consp thing)))
 tree)

#+END_SRC

The above works, yet if I change `tree' to be a plain string "one", it
isn't transformed. I just can't see why.

Eric



reply via email to

[Prev in Thread] Current Thread [Next in Thread]