1

I was following a tutorial on lisp and they did the following code

(set 'x 11)
(incf x 10)

and interpreter gave the following error:

; in: INCF X
;     (SETQ X #:NEW671)
; 
; caught WARNING:
;   undefined variable: X
; 
; compilation unit finished
;   Undefined variable:
;     X
;   caught 1 WARNING condition

21

what is the proper way to increment x ?

Hydrocat
  • 95
  • 1
  • 7

1 Answers1

2

This is indeed how you are meant to increment x, or at least one way of doing so. However it is not how you are meant to bind x. In CL you need to establish a binding for a name before you use it, and you don't do that by just assigning to it. So, for instance, this code (in a fresh CL image) is not legal CL:

(defun bad ()
  (setf y 2))

Typically this will cause a compile-time warning and a run-time error, although it may do something else: its behaviour is not defined.

What you have done, in particular, is actually worse than this: you have rammed a value into the symbol-value of x (with set, which does this), and then assumed that something like (incf x) will work, which it is extremely unlikely to do. For instance consider something like this:

(defun worse ()
  (let ((x 2))
    (set 'x 4)
    (incf x)
    (values x (symbol-value 'x))))

This is (unlike bad) legal code, but it probably does not do what you want it to do.

Many CL implementations do allow assignment to previously unbound variables at the top-level, because in a conversational environment it is convenient. But the exact meaning of such assignments is outwith the language standard.

CMUCL and its derivatives, including SBCL, have historically been rather more serious about this than other implementations were at the time. I think the reason for this is that the interpreter was a bunch more serious than most others and/or they secretly compiled everything anyway and the compiler picked things up.

A further problem is that CL has slightly awkward semantics for top-level variables: if you go to the effort to establish a toplevel binding in the normal way, with defvar & friends, then you also cause the variable to be special -- dynamically scoped -- and this is a pervasive effect: it makes all bindings of that name special. That is often a quite undesirable consequence. CL, as a language, has no notion of a top-level lexical variable.

What many implementations did, therefore, was to have some kind of informal notion of a top-level binding of something which did not imply a special declaration: if you just said (setf x 3) at the toplevel then this would not contage the entire environment. But then there were all sorts of awkward questions: after doing that, what is the result of (symbol-value 'x) for instance?

Fortunately CL is a powerful language, and it is quite possible to define top-level lexical variables within the language. Here is a very hacky implementation called deflexical. Note that there are better implementations out there (including at least one by me, which I can't find right now): this is not meant to be a bullet-proof solution.

(defmacro deflexical (var &optional value)
  ;; Define a cheap-and-nasty global lexical variable.  In this
  ;; implementation, global lexicals are not boundp and the global
  ;; lexical value is not stored in the symbol-value of the symbol.
  ;;
  ;; This implementation is *not* properly thought-through and is
  ;; without question problematic
  `(progn
     (define-symbol-macro ,var (get ',var 'lexical-value))
     (let ((flag (cons nil nil)))
       ;; assign a value only if there is not one already, like DEFVAR
       (when (eq (get ',var 'lexical-value flag) flag)
         (setf (get ',var 'lexical-value) ,value))
       ;; Return the symbol
       ',var)))
  • Looks line I need more reading. Can you suggest a good source ? – Hydrocat Oct 18 '16 at 13:55
  • @Hydrocat: I'm not really the right person to ask: when I learnt CL there was really only CLtL which (while an interesting book) is not really a source of good, current information. I like the Paul Graham books, which I think are now free, and the spec, which is not good to learn from. Perhaps someone else has better & more recent ideas. –  Oct 18 '16 at 16:25
  • Oh, nice :) I actually got a copy of Graham's book. I should be in good hands then ! – Hydrocat Oct 19 '16 at 15:28