setq and defvar in Lisp

前端 未结 4 1404
梦谈多话
梦谈多话 2020-11-27 13:33

I see that the Practical Common Lisp uses (defvar *db* nil) for setting up a global variable. Isn\'t it OK to use setq for the same purpos

4条回答
  •  日久生厌
    2020-11-27 14:28

    defvar introduces a dynamic variable while setq is used to assign a value to a dynamic or lexical variable. The value of a dynamic variable is looked up in the environment that calls the function, while the value of a lexical variable is looked up in the environment where the function was defined. The following example will make the difference clear:

    ;; dynamic variable sample
    > (defvar *x* 100)
    *X*
    > (defun fx () *x*)
    FX
    > (fx)
    100
    > (let ((*x* 500)) (fx)) ;; gets the value of *x* from the dynamic scope.
    500
    > (fx) ;; *x* now refers to the global binding.
    100
    
    ;; example of using a lexical variable
    > (let ((y 200))
       (let ((fy (lambda () (format t "~a~%" y))))
         (funcall fy) ;; => 200
         (let ((y 500))
           (funcall fy) ;; => 200, the value of lexically bound y
           (setq y 500) ;; => y in the current environment is modified
           (funcall fy)) ;; => 200, the value of lexically bound y, which was 
                         ;; unaffected by setq
         (setq y 500) => ;; value of the original y is modified.
         (funcall fy))) ;; => 500, the new value of y in fy's defining environment.
    

    Dynamic variables are useful for passing around a default value. For instance, we can bind the dynamic variable *out* to the standard output, so that it becomes the default output of all io functions. To override this behavior, we just introduce a local binding:

    > (defun my-print (s)
            (format *out* "~a~%" s))
    MY-PRINT
    > (my-print "hello")
    hello
    > (let ((*out* some-stream))
        (my-print " cruel ")) ;; goes to some-stream
    > (my-print " world.")
    world
    

    A common use of lexical variables is in defining closures, to emulate objects with state. In the first example, the variable y in the binding environment of fy effectively became the private state of that function.

    defvar will assign a value to a variable only if it is not already assigned. So the following re-definition of *x* will not change the original binding:

    > (defvar *x* 400)
    *X*
    > *x*
    100
    

    We can assign a new value to *x* by using setq:

    > (setq *x* 400)
    400
    > *x*
    400
    > (fx)
    400
    > (let ((*x* 500)) (fx)) ;; setq changed the binding of *x*, but 
                             ;; its dynamic property still remains.
    500
    > (fx)
    400
    

提交回复
热议问题