programar - ¿Diferencia entre `set`,` setq`, y `setf` en Common Lisp?
programar en common lisp (6)
¿Cuál es la diferencia entre "set", "setq" y "setf" en Common Lisp?
Me gustaría agregar a respuestas anteriores que setf es macro que llama función específica dependiendo de lo que se pasó como su primer argumento. Compare los resultados de la expansión macro de setf con diferentes tipos de argumentos:
(macroexpand ''(setf a 1))
(macroexpand ''(setf (car (list 3 2 1)) 1))
(macroexpand ''(setf (aref #(3 2 1) 0) 1))
Para algunos tipos de argumentos, se llamará "función setf":
(defstruct strct field)
(macroexpand ''(setf (strct-field (make-strct)) 1))
Originalmente, en Lisp, no había variables léxicas, solo dinámicas. Y no había SETQ o SETF, solo la función SET.
Lo que ahora está escrito como:
(setf (symbol-value ''*foo*) 42)
fue escrito como:
(set (quote *foo*) 42)
que finalmente se abrevió a SETQ (SET Quoted):
(setq *foo* 42)
Luego ocurrieron las variables léxicas, y SETQ se usó para asignarlas también a ellas, por lo que ya no era un simple contenedor de SET.
Más tarde, alguien inventó SETF (SET Field) como una forma genérica de asignar valores a las estructuras de datos, para reflejar los valores-l de otros lenguajes:
x.car := 42;
sería escrito como
(setf (car x) 42)
Para simetría y generalidad, SETF también proporcionó la funcionalidad de SETQ. En este punto, habría sido correcto decir que SETQ era una primitiva de nivel bajo y SETF una operación de alto nivel.
Luego, sucedieron macros de símbolos. Para que las macros de símbolos pudieran funcionar de forma transparente, se pensó que SETQ tendría que actuar como SETF si la "variable" a la que se asignaba era realmente una macro de símbolos:
(defvar *hidden* (cons 42 42))
(define-symbol-macro foo (car *hidden*))
foo => 42
(setq foo 13)
foo => 13
*hidden* => (13 . 42)
Así que llegamos al presente: SET y SETQ son restos atrofiados de dialectos antiguos, y probablemente serán iniciados por eventuales sucesores de Common Lisp.
Puede usar setf
en lugar de set
o setq
pero no viceversa, ya que setf
también puede establecer el valor de los elementos individuales de una variable si la variable tiene elementos individuales. Ver los ejemplos a continuación:
Los cuatro ejemplos asignarán la lista (1, 2, 3) a la variable llamada 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
tiene la capacidad adicional de establecer un miembro de la lista en foo
a un nuevo valor.
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)
Sin embargo, puede definir una macro de símbolo que represente un solo elemento dentro de 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)
Puede usar defvar
si aún no ha definido la variable y no desea darle un valor hasta más adelante en su código.
(defvar foo2)
(define-symbol-macro foo-car (car foo2))
Uno puede pensar que SET
y SETQ
son construcciones de bajo nivel.
SET
puede establecer el valor de los símbolos.SETQ
puede establecer el valor de las variables.
Entonces SETF
es una macro, que proporciona muchos tipos de ajustes: símbolos, variables, elementos de matriz, ranuras de instancia, ...
Para símbolos y variables uno puede pensar como si SETF
expande en SET
y SETQ
.
* (macroexpand ''(setf (symbol-value ''a) 10))
(SET ''A 10)
* (macroexpand ''(setf a 10))
(SETQ A 10)
Así que SET
y SETQ
se utilizan para implementar algunas de las funciones de SETF
, que es la construcción más general. Algunas de las otras respuestas te dicen la historia un poco más compleja, cuando tomamos en cuenta las macros de símbolos.
setq
es igual que set
con un primer setq
citado - (set ''foo ''(bar baz))
es como (setq foo ''(bar baz))
. setf
, por otro lado, es muy sutil, es como una "indirección". Sugiero http://www.n-a-n-o.com/lisp/cmucl-tutorials/LISP-tutorial-16.html como una mejor manera de empezar a entenderlo que cualquier respuesta aquí puede dar ... en resumen, setf
toma el primer argumento como una "referencia", de modo que, por ejemplo, (aref myarray 3)
funcionará (como el primer arg a setf
) para establecer un elemento dentro de una matriz.
(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