mappend!невозможно добавить элемент в список, если список пуст? - PullRequest
3 голосов
/ 08 сентября 2011
(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

он выведет:

(mcons 100 '())
'()
(mcons 2 (mcons 100 '()))
(mcons 2 (mcons 100 '()))

Первая и третья строка - это просто возвращаемое значение mappend!Обратите внимание на вторую и четвертую строки!Мы можем видеть, что вторая строка '(), что означает, что mappend!не меняет mlst-my!В то время как mlst-my2 не пусто, mappend! работает нормально. Вопрос: Тогда как сделать карту!по-прежнему побочный эффект млист, когда млист пуст?

1 Ответ

3 голосов
/ 08 сентября 2011

Ты не можешь!Пустой список представляет собой одноэлементный неизменный объект.Он не имеет слотов (автомобиль или CDR), которые вы можете изменить.Но вы можете сделать это:

(set! mlst-my (mappend! mlst-my (list->mlist (list 100))))

То есть вы set! свою переменную для возвращаемого значения mappend!.


Чтобы понять все это, понять как одиночносвязанные списки работают.Он состоит из cons-ячеек (или пунктирных пар ), каждая из которых имеет два слота (традиционно называемые car и cdr).Слот car указывает на значение, а cdr указывает на следующую cons / пару.

Итак, список, подобный (1 2 3), имеет три значения:

#0=(1 . #1#)
#1=(2 . #2#)
#2=(3 . ())

Способ работы append! состоит в том, чтобы найти последние минусы (тот, чей cdr указывает на ()) и изменить его cdr, чтобы он указывал на добавляемый вами список.

ЕслиВаш список пуст, тем не менее, он не имеет смыслов, и поэтому ему нечего менять.Пустые списки всегда неизменны.

...