Добавление элемента в список в схеме - PullRequest
8 голосов
/ 04 июля 2010

Ниже приведен мой код, который принимает элемент car из списка (carVal) и список (инициализированный как пустой) в качестве параметров.Я хочу добавить элемент в список, но он не работает.

(define populateValues
   (lambda (carVal currVal)
      (append currVal(list carVal ))
       (display currVal)))

На дисплее все время отображается пустой список ().Может кто-нибудь помочь мне понять, почему?

Ответы [ 5 ]

25 голосов
/ 05 июля 2010

Ну, есть append! как примитив, который решает большинство ваших проблем, как уже отмечалось, Схема имеет тенденцию хмуриться при мутации, это возможно, но обычно избегается, поэтому все процедуры, которые мутируют, имеют ! (называется взрывом) в конце.

Кроме того, set! не изменяет данные, это изменяет среду , переменная указывает на другую вещь, исходные данные остаются без изменений.

Мутировать данные в Scheme довольно громоздко, но, чтобы дать вам мою собственную реализацию append! чтобы увидеть, как это делается:

(define (append! lst . lsts)
  (if (not (null? lsts))
      (if (null? (cdr lst))
          (begin
            (set-cdr! lst (car lsts))
            (apply append! (car lsts) (cdr lsts)))

          (apply append! (cdr lst) lsts))))

Обратите внимание на использование set-cdr!, который является истинным мутатором, он работает только на парах, он изменяет данные в памяти, в отличие от `set! '. Если пара передается в функцию и видоизменяется с помощью set-cdr! или set-car !, он мутирует везде в программе.

Это подчиняется дополнению SRFI! spec, который говорит, что он должен быть переменным и возвращать неопределенное значение, например.

(define l1 (list 1 2 3 4))

(define l2 (list 2 3 4))

(define l3 (list 3 1))

(append! l1 l2 l3)

l1

l2

l3

Который отображает:

(1 2 3 4 2 3 4 3 1)
(2 3 4 3 1)
(3 1)

Как видно, добавь! может принимать бесконечное количество аргументов, и оно мутирует их всех, кроме последнего.

Хотя схема не может быть идеальным языком для вас. Использование дополнения! как было сказано ранее, является нестандартным, вместо этого предпочтительнее append, который не изменяется и вызывается для его возвращаемого значения. Который я реализую как таковой:

(define (append . lsts)
  (cond
    ((null? lsts) '())
    ((null? (car lsts)) (apply append (cdr lsts)))
    (else (cons (caar lsts) (apply append (cdar lsts) (cdr lsts))))))


> (append (list 1 2 3) (list 4 5 6) (list 'granny 'porn))
(1 2 3 4 5 6 granny porn)

Что показывает более привычный стиль Scheme при отсутствии мутации, интенсивное использование рекурсии и не использовать последовательность.

Редактировать: Если вы просто хотите добавить некоторые элементы в список, а не сами по себе, присоединитесь к двум, хотя:

(define (extend l . xs)
  (if (null? l) 
      xs
      (cons (car l) (apply extend (cdr l) xs))))

(define (extend! l . xs)
  (if (null? (cdr l))
      (set-cdr! l xs)
      (apply extend! (cdr l) xs)))

(extend '(0 1 2 3) 4 5 6)

(define list1 '(0 1 2 3))

(extend! list1 4 5 6)

list1

Что делает то, что вы ожидаете

5 голосов
/ 04 июля 2010
  1. append создает новый список, он не изменяет существующий.
  2. Это потому, что в общем случае Scheme (и в данном случае Racket) - это язык, который предпочитает функциональный стиль.
  3. Вы можете немного приблизиться к set! - но даже это вас разочарует, поскольку оно изменит только локальную привязку.
  4. Обратите внимание, что, в частности, в Racket списки являются неизменяемыми, поэтому ничего не может изменить список.
  5. Кроме того, даже если вы можете изменить список таким образом, это очень неэффективный способ накопления длинных списков, поскольку вам приходится многократно сканировать весь список.
  6. Наконец, если у вас есть проблемы на этом уровне, тогда я настоятельно рекомендую перейти на HtDP
2 голосов
/ 04 июля 2010

(append foo bar) возвращает объединение foo и bar. Не меняется ни foo, ни bar.

0 голосов
/ 16 июля 2010

Вам действительно нужно подумать о том, какую именно функциональность вы ищете

Если вы хотите изменить список ссылок на месте, то вам нужно сделать эквивалент дополнения! (как отмечено в других ответах). Но это опасно, ПОТОМУ ЧТО у вас может быть другой код, который рассчитывает на неизменяемость списка, и если вы собираетесь это сделать, ваша процедура должна иметь! в конце, чтобы пометить эту опасность.

Дешевое приближение к тому, что вы хотите сделать в более функциональном стиле:

(define (populateValues carVal currVal)
 (let ((ll (append currVal (list carVal))))
   (display ll)
   ll))

Обратите внимание, что он создает новый список, добавляет, отображает результат и возвращает новый список в качестве значения. Это полезный метод отладки, если у вас нет доступа к промежуточному значению: свяжите переменную, отобразите или зарегистрируйте ее, а затем верните.

0 голосов
/ 04 июля 2010

Вы должны обновить значение currVal с помощью set !.Ваш пример должен иметь

(set! currVal (append currVal (list carVal))
(display currVal)
...