(require racket/mpair)
(define (bld-mlst . args)
(list->mlist args))
(define mlst-my (bld-mlst))
mlst-my
(mappend! mlst-my (list->mlist (list 100)))
mlst-my
(define mlst-my2 (bld-mlst 2))
(mappend! mlst-my2 (list->mlist (list 100)))
mlst-my2
it will print out:
(mcons 1开发者_JS百科00 '())
'()
(mcons 2 (mcons 100 '()))
(mcons 2 (mcons 100 '()))
The first and third line is just the return value of the mappend! Note the second line and fourth line! We can see that the second line is '()
, which means that mappend! does not change the mlst-my
! While when the mlst-my2
is not empty, the mappend!
works fine.
Question:
Then How to make the mappend! to still side effect the mlist when the mlist is empty?
You can't! The empty list is a singleton, immutable object. It has no slots (car or cdr) that you can change. But you can do this:
(set! mlst-my (mappend! mlst-my (list->mlist (list 100))))
That is, you set!
your variable to mappend!
's return value.
To understand all that, understand how singly linked lists work. It comprises cons cells (or dotted pairs), which each have two slots (traditionally named car
and cdr
). The car
slot points to the value, and the cdr
points to the next cons/pair.
So, a list like (1 2 3)
has three conses:
#0=(1 . #1#)
#1=(2 . #2#)
#2=(3 . ())
The way append!
works is to find the last cons (the one whose cdr
is pointing to ()
), and change its cdr
to point to the list you're appending.
If your list is empty, though, it has no conses, and therefore it has nothing to change. Empty lists are always immutable.
精彩评论