LISP local/global variable assignment

后端 未结 3 1332
情话喂你
情话喂你 2021-02-08 14:02

If we define a function something like

(defun foo(x)
  (setf x somevalue))

Is x defined as a local variable or global? using setf/

3条回答
  •  后悔当初
    2021-02-08 14:20

    To draw a parallel to other languages like C, C++, Java or Python what your code changes is a "local variable" even if this is not a wording that a Lisper would use (the wording in Lisp parlance would be a local "binding").

    You can create local variables by using function parameters like your example does, or using some standard forms like:

    • (let ((x 12)) ...)
    • (do ((x 0 (1+ i))) ...)
    • (dotimes (x 10) ...)
    • (loop for x from 0 to 10 do ...)

    On the other hand it is possible that in your implementation all local variables are created using parameters and other forms simply are macros expanding to that. For example:

    (let ((x 10)) ...)
    

    is equivalent to

    (funcall (lambda (x) ...) 10)
    

    Note also that indeed reading your code fragment it's possible that x is in a sense a "global variable" because it could have been declared special:

    (defvar x 12)
    ;; ==> x
    
    (defun bar ()
      (format t "The value of x is ~a" x))
    ;; ==> bar
    
    (defun foo (x)
      (bar))
    ;; ==> foo
    
    (foo 42)
    The value of x is 42
    ;; ==> NIL
    
    x
    ;; ==> 12
    

    If you declare a variable "special" using (defvar ...) it will be handled differently: it's like every time you use it as a parameter or you use it in a (let ..) form what the code will do is saving the current value, using the new provided value and then restoring the value after you exit the function or let.

    So those variables are both "global" (because outer functions can see them) but also local (because after your function or let terminates the previous value will be restored).

    The standard convention is to name special variables with "earmuffs" i.e. with an asterisk both at the start and at the end of the name like:

    (defvar *x* 12)
    

    This helps who reads your code to understand that the variable is special. Note that however this is not mandated by the language and any name can be used for a special variable.

    There is nothing similar to special variables in C, C++, Java or Python.

    One last note about setq and setf. Things are a bit tricky here because you need to understand lower levels of Lisp to see why setq is needed. If you are using Common Lisp then you should simply forget about setq and always use setf.

    setf is a macro that will expand to setq when needed (however also setq can change into setf when needed (symbol macros) and this is where things may get confusing for a newbie).

    Your last example is a case of a "closure". When you define a function (either named or unnamed with a (lambda ...) form) the function can "capture" the variables that are visible and use them later. A simpler case often shown is the "adder":

    (defun adder (x)
      (lambda (y) (incf x y)))
    

    this function returns a function that will keep adding the passed value to an internal totalizer:

    (let ((f (adder 10)))
      (print (funcall f 3))
      (print (funcall f 9))
      (print (funcall f 11)))
    

    the output will be 13 (10 + 3), 22 (13 + 9) and 33 (22 + 11).

    The anonymous function "captured" the local variable x and can use it even after exiting the adder function. In languages like C, C++ or Java a local variable cannot survive when you exit the scope that defined the variable.

    C++11 has unnamed functions, but still variables cannot be captured and survive the scope (they can be copied to local variables of the unnamed function, but this is not the same thing).

提交回复
热议问题