tutorial programar programacion net lenguaje español compiler common common-lisp

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