There is this procedure giving me trouble:
(define (pro lst)
(define (inner l)
(if (null? (mcdr l))
(set-mcdr! l lst)
(inner (mcdr l))))
(inner lst)
lst)
Using (mlist 1 2 3) as parameter I get #0={1 2 3 . #0#} returned.
(mcdr (pro (mlist 1 2 3))) returns #0={2 3 1 . #0#},
(mcdr (mcdr (pro (mlist 1 2 3)))) returns #0={3 1 2 . #0#} and so on.
So obviously this is for cycling through lists by returning a pair of a list and another procedure. But how does this work? I only see that it replaces the final'() with the parameter lst but not with any obscure lambda function …
What do #0 and #0# mean anyway?
In the expression
#0={1 2 3 . #0#}, think of#0=as an anchor and#0#as a link to that anchor – that is, in the list the first three elements are1 2 3but the fourth element is a pointer to the start of the list, therefore forming a three-element circular list. If you keep advancing over that list (by successivemcdrs), you’ll see a three element list in a cycling pattern1 2 3 1 2 3 ..., always showing that the fourth element jumps back to the first.Studying the above function makes it clear why this is happenning. The
proprocedure simply callsinneron thelstparameter (a proper list, a list withnullas its last element) and then returns the modifiedlst, the interesting part is what happens ininner:(if (null? (mcdr l)): If we’re on the last non-null element of the list, replace the next element (which should be anullin a proper list), by a reference to the first element, which we know is in thelstparameter:(set-mcdr! l lst)(inner (mcdr l))To summarize: the
proprocedure gets as its input a proper list and returns the same list but with the last element pointing back to its first element – a circular list.