Как перебрать каждый элемент в списке, не удаляя элементы в схеме

Моя проблема состоит в том, чтобы сделать простую программу плюс-минус на языке Racket R5RS. Основная идея задачи состоит в том, чтобы поставить знаки плюс/минус перед каждым элементом в списке и проверить, является ли результат одним из элементов в списке. Ниже то, что у меня есть прямо сейчас:

(define plus-minus (lambda (lst l sum)
                (cond
                  ((null? lst)
                   (cond
                     ((null? l) #f)
                     ((= sum (car l)) #t)
                     (else (plus-minus lst (cdr l) sum))))
                  ((plus-minus (cdr lst) l (+ sum (car lst))) #t)
                  ((plus-minus (cdr lst) l (- sum (car lst))) #t)
                  (else #f))))

Этот код рабочий, но требуется, чтобы в параметрах был один и только один список, а все остальные числа. Первые два параметра в моем коде идентичны при первом вызове функции. Первый получает сумму. Второй — проверить, равна ли сумма одному из элементов списка. Оба списка необходимы, потому что, когда я получаю сумму, элементы в первом списке удаляются.
Мой вопрос: как избавиться от второго списка в параметрах? Могу ли я в любом случае перебирать список, не удаляя элементы (рекомендация CDR)?


person S.Y    schedule 29.04.2016    source источник


Ответы (1)


Прежде всего, часть вашего кода

(cond
  ((null? l) #f)
  ((= sum (car l)) #t)
  (else (plus-minus lst (cdr l) sum))))

состоит в том, чтобы проверить, находится ли sum в l или нет. Для этого уже есть функция member, так что вы можете заменить весь фрагмент на (member sum l), что чище.

Я тоже хочу сначала исправить заблуждение. cdr не удаляет элемент из списка. Список определяется либо как пустой список, либо как пара элемента и другого списка. Например

[1 [2 [3 empty]]]

представляет собой список, состоящий из трех элементов: 1, 2 и 3. Что делает car, так это извлекает первый элемент пары. Что делает cdr, так это извлекает второй элемент пары. Ничего не удаляется.

Чтобы избавиться от дополнительных аргументов, вы можете переименовать эту функцию в другую функцию, скажем, plus-minus-helper, и создать plus-minus, которая затем вызывает plus-minus-helper. plus-minus тогда будет:

(define (plus-minus lst)
  (plus-minus-helper lst lst 0))

В качестве альтернативы, если вы хотите сделать все в одной функции, вы также можете использовать letrec для привязки plus-minus-helper внутри plus-minus или использовать форму let letrec. Этими способами вы также можете ссылаться на исходный аргумент ввода, поэтому вам не нужен еще один аргумент.

(define (plus-minus init-lst)
  (let plus-minus-helper ((lst init-lst)
                          (sum 0))
    (cond
      ((null? lst) (member sum init-lst))
      ((plus-minus-helper (cdr lst) (+ sum (car lst))) #t)
      ((plus-minus-helper (cdr lst) (- sum (car lst))) #t)
      (else #f))))
person Sorawee Porncharoenwase    schedule 29.04.2016