Есть ли в языке схем нормальная функция "set" (не специальная форма)? - PullRequest
1 голос
/ 03 августа 2020

Есть ли обычная функция «set» (не в специальной форме) на языке Scheme или какой-либо способ ее реализовать?

Я бы хотел написать код примерно так:

(map (lambda (var)
       (set var 0))
     '(a b c))

который мог бы присвоить значение (здесь это '0') переменным из списка (здесь это 'a', 'b' и 'c').

Ответы [ 2 ]

3 голосов
/ 04 августа 2020

Нет. И чтобы понять, почему здесь нет, рассмотрите что-то вроде этого:

(define (mutant var val)
  (let ((x 1))
    (set var val)
    x))

Что должно возвращать (mutant 'x 3)? Если он должен вернуть 3, тогда:

  • set не может быть функцией, так как ему нужен доступ к лексической среде mutant;
  • любого вида разумная компиляция этой функции невозможна.

Если вы хотите, чтобы set была функцией, то последует катастрофа. Рассмотрим это определение:

(define (mutant-horror f)
  (let ([x 3])
    (f)
    x))

Теперь вы можете подумать, что это можно оптимизировать до следующего:

(define (mutant-horror f)
  (f)
  3)

Но это невозможно. Потому что вы могли бы назвать это так:

(mutant-horror (λ () (set 'x 3)))

или, в более общем смысле, вы могли бы вызвать его с помощью функции, которая где-то в конечном итоге в какой-то функции, вызываемой косвенно из нее, может в конечном итоге сказать (set 'x 3). *

Это означает, что никакая привязка вообще не может быть оптимизирована , что является катастрофой. Это также, по крайней мере, очень близко к тому, что означает, что лексическая область видимости невозможна: если наряду с set существует функция с именем get, которая извлекает привязку символа, то у вас, по сути, есть динамическая c область. Это, в свою очередь, делает такие вещи, как устранение хвостовых вызовов, по крайней мере, трудными и, вероятно, невозможными (на самом деле set, вероятно, делает это само по себе). 1036 * действительно существовал и работал поверхностно, фактически делал специальные исключения для скомпилированного кода, где set не не работал (см., Например, руководство программиста Lisp 1.5 (ссылка в PDF) , приложение D. Это расхождение между семантикой скомпилированного и интерпретируемого кода - одна из вещей, с которыми позже покончили с Lisps и связанными с Lisp языками, такими как CL и Scheme.

Если вместо этого вы хотите что-то вроде семантики Common Lisp, где эквивалентная вещь

(defun mutant (var val)
  (let ((x 1))
    (set var val)
    x))

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

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

(defun mutant/local-special (a b)
  (let ((x 1))
    (declare (special x))
    (set a b)
    x))

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

1 голос
/ 04 августа 2020

Когда вы пишете что-то вроде

(map (lambda (var)
       (set var 0))
     '(a b c))

, моя первая мысль заключалась в том, что вы пытаетесь накапливать неупорядоченные наборы формы ( (a 0) (b 0) (c 0) ).

Вы не можете реализовать свой собственный сеттер для любого из внутренние структуры данных, предоставляемые языком, поскольку это означало бы написать функцию схемы для изменения некоторых структур данных, реализованных в C. Для структур данных, реализованных в C, вам необходимо предоставить сеттеры, написанные на C - предположим, что нижний язык - C.

Если вы хотите реализовать свой собственный сеттер, вы либо

- проверьте, как реализована структура данных, и если она реализована в схеме, вы поймете, как ее изменить.

- определите свою собственную структуру данных, используя уже существующие структуры данных, и определите для нее сеттеры.

Сеттер, изменяющий структуру данных, содержит ! в конце своего имени, например set!, append!, et c.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...