В чем разница между "set", "setq" и "setf" в Common Lisp?
common-lisp
Ричард Хоскинс
источник
источник
Ответы:
Первоначально в Лиспе не было лексических переменных - только динамические. И не было никакого SETQ или SETF, только функция SET.
Что сейчас написано как:
был написан как:
который в конечном итоге был сокращен до SETQ (SET Quoted):
Затем произошли лексические переменные, и SETQ стал использоваться для их присвоения - так что это больше не было простой оберткой вокруг SET.
Позже кто-то изобрел SETF (SET Field) как общий способ присвоения значений структурам данных, чтобы отразить l-значения других языков:
будет написано как
Для симметрии и общности SETF также предоставил функциональность SETQ. В этот момент было бы правильно сказать, что SETQ - это низкоуровневый примитив, а SETF - высокоуровневая операция.
Затем произошли макросы символов. Чтобы эти символьные макросы могли работать прозрачно, стало понятно, что SETQ должен будет действовать как SETF, если назначаемая «переменная» действительно является символьным макросом:
Итак, мы прибываем в сегодняшний день: SET и SETQ являются атрофированными остатками старых диалектов и, вероятно, будут загружены из возможных преемников Common Lisp.
источник
f
самом деле обозначает функцию , а не поле (или форму , если на то пошло), и предоставляет ссылки, поэтому, хотя setf for field имеет некоторый смысл, похоже, что оно может быть неверным.set
это функция. Таким образом, он не знает окружающей среды.set
не может видеть лексическую переменную. Он может установить только значение символа своего аргумента.setq
больше не «ставить в кавычки». Тот факт, чтоsetq
это особая форма, а не макрос, показывает это.источник
(setq ls '(((1))))
,(setf (car (car (car ls))) 5)
неопределенное поведение, потому что значениеls
является постоянным (как изменение строкового литерала в C). После того, как(setq ls (list (list (list 1))))
,(setf (car (car (car ls))) 5)
работает так же , как иls->val->val->val = 5
в С.setq
так же, какset
с первым аргументом в кавычках - так(set 'foo '(bar baz))
же, как(setq foo '(bar baz))
.setf
С другой стороны, это действительно тонко - это как «косвенность». Я предлагаю http://www.nano.com/lisp/cmucl-tutorials/LISP-tutorial-16.html как лучший способ начать понимать это, чем любой ответ здесь может дать ... короче, однако,setf
берет Первый аргумент в качестве «ссылки», так что, например,(aref myarray 3)
будет работать (как первый аргументsetf
), чтобы установить элемент внутри массива.источник
Вы можете использовать
setf
вместоset
или,setq
но не наоборот, так какsetf
можете также установить значение отдельных элементов переменной, если переменная имеет отдельные элементы. Смотрите примеры ниже:Все четыре примера назначат список (1, 2, 3) переменной с именем foo.
setf
имеет добавленную возможность установки члена списка вfoo
новое значение.Тем не менее, вы можете определить макрос символа, который представляет один элемент в
foo
Вы можете использовать,
defvar
если вы еще не определили переменную и не хотите давать ей значение до тех пор, пока в вашем коде не будет.источник
Можно думать
SET
иSETQ
о низкоуровневых конструкциях.SET
можно установить значение символов.SETQ
Можно установить значение переменных.Затем
SETF
выполняется макрос, который предоставляет множество видов настроек: символы, переменные, элементы массива, слоты экземпляров, ...Для символов и переменных можно думать, как будто
SETF
расширяется вSET
иSETQ
.Поэтому
SET
иSETQ
используются для реализации некоторых функцийSETF
, которые являются более общей конструкцией. Некоторые другие ответы рассказывают вам немного более сложную историю, когда мы принимаем во внимание символьные макросы.источник
Я хотел бы добавить к предыдущим ответам, что setf - это макрос, который вызывает конкретную функцию в зависимости от того, что было передано в качестве первого аргумента. Сравните результаты макроразложения setf с различными типами аргументов:
Для некоторых типов аргументов будет вызываться функция setf:
источник