Разница между "set", "setq" и "setf" в Common Lisp?


в чем разница между "set", "setq" и "setf" в Common Lisp?

6 139

6 ответов:

первоначально в Lisp не было лексических переменных-только динамические. И не было никакого SETQ или SETF, только функция SET.

что теперь пишется как:

(setf (symbol-value '*foo*) 42)

было написано так:

(set (quote *foo*) 42)

который в конечном итоге был сокращен до SETQ (SET Quoted):

(setq *foo* 42)

затем произошли лексические переменные, и SETQ стал использоваться для присвоения им тоже-так что это больше не была простая обертка вокруг набора.

, кто-то придумал SETF (SET Field) как общий способ присвоения значений структурам данных, чтобы отразить l-значения других языков:
x.car := 42;

было бы написано как

(setf (car x) 42)

для симметрии и общности SETF также предоставляет функциональность SETQ. На этом этапе было бы правильно сказать, что SETQ был примитивом низкого уровня, а SETF-операцией высокого уровня.

затем произошли макросы символов. Чтобы макросы символов могли работать прозрачно, это было реализовано, что SETQ должен был бы действовать как SETF, если бы" переменная", назначаемая на самом деле, была макросом символа:

(defvar *hidden* (cons 42 42))
(define-symbol-macro foo (car *hidden*))

foo => 42

(setq foo 13)

foo => 13

*hidden* => (13 . 42)

Итак, мы приходим в настоящее время: SET и SETQ являются атрофированными остатками старых диалектов и, вероятно, будут загружены из возможных преемников Common Lisp.

(set ls '(1 2 3 4)) => Error - ls has no value

(set 'ls '(1 2 3 4)) => OK

(setq ls '(1 2 3 4)) => OK - make ls to (quote ls) and then have the usual set

(setf ls '(1 2 3 4)) => OK - same as setq so far BUT

(setf (car ls) 10) => Makes ls '(10 2 3 4) - not duplicated by setq/set

setq Как set с процитированным первым аргументом -- (set 'foo '(bar baz)) как (setq foo '(bar baz)). setf, С другой стороны, это действительно тонкий-это как "косвенность". Я предлагаю http://www.n-a-n-o.com/lisp/cmucl-tutorials/LISP-tutorial-16.html как лучший способ начать понимать это, чем любой ответ здесь может дать... короче говоря, хотя,setf принимает первый аргумент в качестве "ссылки", так что, например,(aref myarray 3) будет работать (как первый arg к setf), чтобы установить элемент внутри массива.

можно использовать setf на месте set или setq но не наоборот, поскольку setf также можно установить значение отдельных элементов переменной, если переменная имеет отдельные элементы. Смотрите примеры ниже:

все четыре примера присвоят список (1, 2, 3) переменной с именем foo.

(set (quote foo) (list 1 2 3))    ;foo => (1 2 3)
(1 2 3)

(set 'foo '(1 2 3))   ;foo => (1 2 3) same function, simpler expression
(1 2 3)

(setq foo '(1 2 3))   ;foo => (1 2 3) similar function, different syntax
(1 2 3)

(setf foo '(1 2 3))   ;foo => (1 2 3) more capable function
(1 2 3)

setf имеет дополнительную возможность установки члена списка в foo новое значение.

foo                   ;foo => (1 2 3) as defined above
(1 2 3)

(car foo)             ;the first item in foo is 1
1

(setf (car foo) 4)    ;set or setq will fail since (car foo) is not a symbol
4

foo                   ;the fist item in foo was set to 4 by setf
(4 2 3)

тем не менее, вы можете определить a символ макроса, который реприентирует один элемент в foo

(define-symbol-macro foo-car (car foo))    ; assumes FOO => (1 2 3)
FOO-CAR

foo-car               ;foo-car is now a symbol for the 1st item in foo
1

(setq foo-car 4)      ;set or setq can set the symbol foo-car 
4

foo                   ;Lisp macros are so cool
(4 2 3)

можно использовать defvar если вы еще не определили переменную и не хочу давать ей значение, пока в коде.

(defvar foo2)
(define-symbol-macro foo-car (car foo2))

кажется SET и SETQ будучи низкоуровневыми конструкциями.

  • SET можно установить значение символов.

  • SETQ можно установить значение переменных.

затем SETF - это макрос, который предоставляет множество видов настроек: символы, переменные, элементы массива, слоты экземпляров, ...

для символов и переменных можно думать, как будто SETF превращается в SET и SETQ.

* (macroexpand '(setf (symbol-value 'a) 10))

(SET 'A 10)


* (macroexpand '(setf a 10))         

(SETQ A 10)

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

Я хотел бы добавить к предыдущим ответам, что setf-это макрос, который вызывает определенную функцию в зависимости от того, что было передано в качестве ее первого аргумента. Сравните результаты макрорасширения setf с различными типами аргументов:

(macroexpand '(setf a 1))

(macroexpand '(setf (car (list 3 2 1)) 1))

(macroexpand '(setf (aref #(3 2 1) 0) 1))

для некоторых типов аргументов будет вызвана функция setf:

(defstruct strct field)
(macroexpand '(setf (strct-field (make-strct)) 1))