[Top][All Lists]

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

Re: "push" creating circular objects

From: Pascal J. Bourguignon
Subject: Re: "push" creating circular objects
Date: Thu, 21 Aug 2008 20:41:27 +0200
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/22.2 (gnu/linux)

Charles Sebold <address@hidden> writes:

> On Aug 20, 4:50 pm, weber <address@hidden> wrote:
>> Minor variation:
>> (defun test2 (str)
>>   (let (my-list)
>>         (with-temp-buffer
>>           (insert str)
>>           (goto-char (point-min))
>>           (while (not (eobp))
>>                 (cond
>>                   ((= (char-after) ?#)
>>                    (push "ol" my-list))
>>                   ((= (char-after) ?*)
>>                    (push "ul" my-list)))
>>                 (forward-char 1)))
>>         my-list))
>> no need to bind my-list to nil too :)
> Useful tip, thanks.
> Astoundingly I'm still having the same problem, when I run this in the
> context of the larger program.  Against the string "** " it returns
> the circular list (#1="ul" #1#).  In the scratch buffer it works (same
> as with my function earlier).

This is not a circular list, so whatever you may try or infer from
that will be wrong.

> So, I must be rebinding something else in a bad way, but heck if I
> know how.  I'm going to try to trim the whole problem down to a bare
> minimum test case and then if I can't figure it out I'll post the
> whole thing and ask people to eval and see what they can come up
> with.  Thanks for your time.

(defun circular-length (list)
  "LIST must be either a proper-list or a circular-list, not a dotted-list.
RETURN: the total length ; the length of the stem ; the length of the circle.
  (let ((indexes (make-hash-table)))
       for i from 0
       for current on list
       do (let ((index (gethash current indexes)))
             (if index
                 ;; found loop
                 (return (values i index (- i index)))
                 (setf (gethash current indexes) i)))
       finally (return (values i)))))

(circular-length '(a b c d e))
--> (5)

(circular-length '(#1=a b #1# d #1#))
--> (5)

(circular-length '#1=(a b c d e . #1#))
--> (5 0 5)

(circular-length '(a b . #1=(c d e . #1#)))
--> (5 2 3)

Since (#1="ul" #1#) is not a circular list, you can print it without 

(defun print-safely (object)
   (let ((print-circle  (rest (circular-length object))))
      (print object)))

(print-safely '(a b c d e))
prints: (a b c d e)
(print-safely  '#1=(a b c d e . #1#))
prints: #1=(a b c d e . #1#)

(print-safely '(#1=a b #1# d #1#))
prints: (a b a d a)

(print-safely '(#1="ul" #1#))
prints: ("ul" "ul")

So what's the difference between ("ul" "ul") and (#1="ul" #1#)?

It's that in ("ul" "ul") we have two different string objects that
happen to contain the same characters in the same order, while in
(#1="ul" #1#) we have the same string object twice:

(let ((items '(#1="ul" #1#)))
   (eq (first items) (second items)))
--> t

(let ((items '("ul" "ul")))
   (eq (first items) (second items)))
--> nil

__Pascal Bourguignon__           

ADVISORY: There is an extremely small but nonzero chance that,
through a process known as "tunneling," this product may
spontaneously disappear from its present location and reappear at
any random place in the universe, including your neighbor's
domicile. The manufacturer will not be responsible for any damages
or inconveniences that may result.

reply via email to

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