it-swarm.com.ru

Добавление элемента в список в схеме

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

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

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

8
name_masked

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

Кроме того, 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, который говорит, что он должен быть variadic и что он должен возвращать неопределенное значение, например.

(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

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

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

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

2
sepp2k

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

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

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

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

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

0
Dak

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

(set! currVal (append currVal (list carVal))
(display currVal)
0
keithm