@@ -74,11 +74,36 @@ rules provided in the r7rs-small specification.
74
74
(character (typecase y (character (char= x y))))
75
75
(t (eq x y))))
76
76
77
- ; ;; TODO: Must always terminate even if the list is circular.
78
- (defun list-equal? (x y)
79
- (or (and (null x) (eql x y))
80
- (and (equal? (car x) (car y))
81
- (list-equal? (cdr x) (cdr y)))))
77
+ ; ;; TODO: If circular and equal?, then this iterates too much because
78
+ ; ;; it goes to the first detected part of the cycle rather than to the
79
+ ; ;; start of it. It can't just stop at the detection of the cycle
80
+ ; ;; because of e.g. '(-1 0 . #1=(1 2 3 4 5 6 7 8 9 . #1#))
81
+ (define-function list-equal? ((list1 list ) (list2 list ))
82
+ ; ; Note: Tested in a more verbose way so that the list lengths match
83
+ ; ; in the ALWAYS test and so lists with cycles always terminate.
84
+ (loop :with end? := nil
85
+ :with cycle-x := nil
86
+ :with cycle-y := nil
87
+ :for x := list1 :then (cdr x)
88
+ :for y := list2 :then (cdr y)
89
+ ; ; For cycle testing to ensure termination
90
+ :for x-fast := list1 :then (cddr x-fast)
91
+ :for y-fast := list2 :then (cddr y-fast)
92
+ :for i :from 0
93
+ :until end?
94
+ ; ; Recursive equality test
95
+ :always (or (and (endp x) (endp y))
96
+ (equal? (car x) (car y)))
97
+ :do
98
+ ; ; End test
99
+ (when (or (endp x) (endp y) (eq x cycle-x) (eq y cycle-y))
100
+ (setf end? t ))
101
+ ; ; Cycle tests
102
+ (when (plusp i)
103
+ (when (and x-fast (not cycle-x) (eq x x-fast))
104
+ (setf cycle-x x))
105
+ (when (and y-fast (not cycle-y) (eq y y-fast))
106
+ (setf cycle-y y)))))
82
107
83
108
(defun vector-equal? (x y)
84
109
(and (typep y (type-of x))
0 commit comments