2009-07-03 4 views
3

Я изучаю схему R5RS на данный момент (из PocketScheme), и я обнаружил, что могу использовать функцию, встроенную в некоторые варианты Схемы, но не все: Append!Добавить! в Схеме?

Иными словами - деструктивно меняя список.

Меня не интересует фактический код как ответ, а также понимание процесса, посредством которого можно передать список как функцию (или вектор или строку), а затем изменить его.

пример:

(define (append! lst var) 
    (cons (lst var)) 
) 

Когда я использую подход, как указано выше, я должен сделать что-то вроде (define list (append! foo (bar)), который я хотел бы что-то более общий характер.

ответ

5

Мутация, хотя и разрешена, настоятельно не рекомендуется на Схеме. PLT даже зашел так далеко, что удалил set-car! и set-cdr! (хотя они «заменили» их set-mcar! и set-mcdr!). Однако спецификация для append! появилась в SRFI-1. Это append! немного отличается от вашего. В SRFI реализация может, но не требуется, чтобы изменить ячейки cons для добавления списков.

Если вы хотите иметь append!, который гарантированно изменить структуру списка, который будучи добавленным к, вы, вероятно, придется написать его самостоятельно. Это не трудно:

(define (my-append! a b) 
    (if (null? (cdr a)) 
     (set-cdr! a b) 
     (my-append! (cdr a) b))) 

Чтобы сохранить определение просто, нет проверки здесь ошибка, но ясно, что вам нужно будет перейти в список длиной не менее 1, как a, и (предпочтительно) список (любой длины) как b. Причина a должна быть не менее 1, потому что вы не можете set-cdr! в пустом списке.

Поскольку вас интересует, как это работает, я посмотрю, смогу ли я объяснить. В принципе, мы хотим спуститься по списку a, пока не дойдем до последней пары cons, которая равна (<last element> . null). Поэтому сначала мы видим, что a уже является последним элементом в списке, проверив null в cdr. Если это так, мы используем set-cdr!, чтобы установить его в список, который мы добавляем, и мы закончили. Если нет, мы должны позвонить my-append! по телефону cdr из a. Каждый раз, когда мы делаем это, мы приближаемся к концу a. Поскольку это операция мутации, мы ничего не вернем, поэтому нам не нужно беспокоиться о том, чтобы сформировать наш измененный список в качестве возвращаемого значения.

+0

Последующий вопрос - если мутация сильно обескуражена, то что лучше всего подходит для шаблона типа «создание списка из диалогового окна мастера»? Исходя из фона Ruby, это то, с чем я боролся с пониманием ... мышление moreso, чем просто фактический код для решения проблемы. –

+0

В функциональном программировании, когда вы хотите изменить структуру данных или что-то подобное, вы передаете ее в функцию и возвращаете модифицированную структуру данных в качестве возврата. Однако «оригинальная» структура остается нетронутой, и то, что вам дано, это новая, измененная копия (так сказать). –

+0

Возможна полная гарантия, что является проблемой с деструктивными функциями - если список пуст, то никакая версия 'append!' Никогда не сможет его модифицировать. –

0

Лучше поздно, чем никогда для сдачи в паре 2-3 цента на эту тему ...

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

(2) Я думаю ПРИЛОЖЕНИЕ! должен вести себя как APPEND, только (потенциально) разрушительно. И так ПРИЛОЖИТЕ! следует ожидать любое количество списков в качестве аргументов. Каждый список, кроме последнего, предположительно будет SET-CDR! 'D к следующему.

(3) Вышеприведенное определение APPEND! это, по сути, NCONC от Mac Lisp и Common Lisp. (И другие листки).

 Смежные вопросы

  • Нет связанных вопросов^_^