Open dragoncoder047 opened 2 years ago
In fact, you don't need the print because after the setf it returns:
(a a a a a a ...
I've tried it on LispWorks and the same thing happens, so this isn't unique to uLisp. I think at least it should allow you to escape with "~".
I'm not convinced that your proposed solution would work, because structures with shared sublists need not be recursive.
By the way, you raise a number of interesting points, and it's a shame that you don't discuss them on the uLisp forum as I think they would be of interest to other uLisp users. Would you like me to set you up with a login?
structures with shared sublists need not be recursive
Here's an example:
> (defvar a '(x y z))
a
15862> (defvar b (cons a a))
b
15858> b
((x y z) x y z)
15858> (setf (car (car b)) 'w)
w
15858> b
((w y z) w y z)
I'm not convinced that your proposed solution would work, because structures with shared sublists need not be recursive.
Most Lisps don't choke on the setf
, because all that does is create an object that points to itself. In moemory that is totally okay, and I have heard people use it to create a circular linked list (by nconc
'ing a list onto itself). It fails on the print
because the printer isn't smart enough to recognize the reference cycle. (I tried GNU Clisp, and it fails in the same way.) Consider what Python does when it gets to an object that points to itself:
x = list()
x.append(x)
print(x) # prints [[...]] -- the ... indicating it has detected a recursive structure.
AFAIK, the way Python does that is by keeping track of which objects in the pointer structure it has already printed, and when it detects a reference cycle, it prints ...
instead. markobject
does this already anyway; it checks to see if it is marked already and aborts if it is. print
can do the same by marking each object after it is printed, and then unmarking everything when it is done.
If it isn't recursive, nothing bad will ever happen (even in the current uLisp), because there are no reference cycles.
By the way, you raise a number of interesting points, and it's a shame that you don't discuss them on the uLisp forum as I think they would be of interest to other uLisp users. Would you like me to set you up with a login?
No. I'll set one up myself when I feel it would be necessary.
perhaps another example would help:
(defvar x '(1 (2 nil) 3))
(setf (car (cdr (cdr x))) x)
; now x is (1 (2 x) 3)
(print x) ; prints (1 (2 (1 (2 (1 (2 (1 (2 ... forever, never gets to the 3
x = [1, [2, None], 3]
x[1][1] = x
print(x) # prints [1, [2, [...]], 3]
Yes, I understand, and I agree it would be nice to provide this if possible, but I think it goes a bit beyond what's needed for uLisp. I doubt if any uLisp user will be relying on circular lists.
(defvar x '(a)) (setf (cdr x) x) (print x) ;; prints (a a a a a a a a ... forever
I just tried this and it just goes forever, no crash, but the printing can't be interrupted with ~
. Maybe this should be fixed?
Interestingly enough, (setf (car x) x)
(so that the printer won't take the tail-optimized path) only gets to (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((Guru Meditation Error: Stack canary watchpoint triggered (loopTask)
. I didn't realize I had such little stack space!
I just tried this and it just goes forever, no crash, but the printing can't be interrupted with ~.
Yes, fair enough, I could call testescape() within printobject(), although someone would have to go out of their way to have this problem.
Interestingly enough, (setf (car x) x) (so that the printer won't take the tail-optimized path) only gets to ...
Harder to solve that one.
Thanks!
Harder to solve that one.
Yeah, I had the same problem where I tried to implement a cyclic object detector that works be able to allow the printer to automatically print it out as #0=(#0# . nil)
and not crash. I could tail optimize the cdr, but car pointers caused infinite recursion just like the way uLisp is now.
Do you have any ideas/experience on detecting shared structure (for this and for also printing objects like (#0=(123) #0#)
that have shared structure but are not self-referential)?
LispWorks prints it as:
> (defvar y '(a))
Y
> (setf (car y) y)
((((#))))
Not sure how to detect that.
LispWorks prints it as:
> (defvar y '(a)) Y > (setf (car y) y) ((((#))))
Try setting your *print-level*
to nil
to make it print out the entire structure and not bail if it is nested deeply. If it prints forever or crashes, then that means LispWorks doesn't have any kind of cycle detection.
*print-level*
controls how many levels deep a nested object will print. If it is false, then no control is exercised. Otherwise, it is an integer indicating the maximum level to be printed. An object to be printed is at level 0; its components (as of a list or vector) are at level 1; and so on. If an object to be recursively printed has components and is at a level equal to or greater than the value of*print-level*
, then the object is printed as#
.
There should be a way to mark objects during printing and then clear the mark, so that instead of printing infinitely, the above would print
(a <recursive>)
or something similar.My idea for a solution:
Then
supersub
can mark each object after it prints it, and thenmarkobject(obj, false)
to clear the mark before returning. If it hits a marked object it prints<recursive>
and returns without going any farther.