Symbols and Lambda Functions
This chapter covers more advanced concepts that showcase the richness and elegance of LISP. Symbols and lambda functions will allow you to write more expressive and powerful code. These concepts are less common in everyday AutoLISP scripts, but understanding them will give you a much deeper mastery of the language.
Symbols
In AutoLISP, a symbol is a name that references a value. When you write (setq radius 42), radius is a symbol that is bound to the value 42. Think of it as a label on a box that contains the value 42.

When AutoLISP encounters a symbol, it evaluates it automatically — meaning it replaces it with its value:
(setq radius 42)
radius ; → 42 (the symbol is evaluated)
Reminder: in AutoCAD's command line, you must prefix the symbol with
!to get its value (e.g.,!radius). In a.lspprogram or in VS Code's debug console, this prefix is not needed.
But what happens if you want to refer to the symbol itself, without evaluating it? That's where quote comes in.
Quoting with quote and '
The quote function (or its shorthand ') prevents the evaluation of an expression:
(quote radius) ; → radius (the symbol itself, not its value)
'radius ; → radius (identical, shorthand syntax)
Compare:
(setq radius 42)
radius ; → 42 (evaluation: returns the value)
'radius ; → radius (quoting: returns the symbol)

This is exactly the mechanism you used to create literal lists:
'(1 2 3) ; → (1 2 3) — the list is not evaluated as a function call
(list 1 2 3) ; → (1 2 3) — same result, but via a function call
Without the apostrophe, (1 2 3) would be interpreted as a call to the "function" 1, which would cause an error.
The distinction between quote and list is important in practice. With quote, the entire content is frozen — no variables are evaluated. With list, the arguments are evaluated before the list is built. Consider this example of a filter for ssget:
;; The layer name is known in advance: quote is sufficient
(ssget "X" '((8 . "DIMENSION")))
;; The layer name is in a variable: you must use list
;; so that the variable is evaluated
(setq layer-name (getstring "\nLayer name: "))
(ssget "X" (list (cons 8 layer-name)))
With '((8 . layer-name)), AutoLISP would literally search for a layer named "LAYER-NAME" instead of using the value entered by the user.
eval: forcing evaluation
eval is the opposite of quote. It evaluates an expression:
(setq expression '(+ 2 3))
expression ; → (+ 2 3) — it's a list, not a result
(eval expression) ; → 5 — the list is evaluated as code
This is a remarkable capability: in LISP, code and data share the same structure (lists). You can therefore build code dynamically and execute it with eval.
;; Build an expression dynamically
(setq operator '+)
(setq data '(10 20 30))
(eval (cons operator data)) ; → 60 — evaluates (+ 10 20 30)
set vs setq
You already know setq. The set function is its "unquoted" version:
(setq x 10) ; Assigns 10 to the symbol x
(set 'x 10) ; Identical: assigns 10 to the symbol x
setq is a shorthand for set quote — it automatically quotes the first argument. But set is useful when the variable name is itself dynamic:
(setq variable-name 'my-value)
(set variable-name 42)
my-value ; → 42
In practice, you will almost always use setq. But knowing that set exists helps you understand the internal workings of the language.
Lambda functions
A lambda function is an anonymous function — a function without a name. It is defined using the lambda keyword:
(lambda (x) (* x x))
This expression creates a function that takes an argument x and returns x². But since it has no name, how do you use it?
Calling a lambda directly
You can call it immediately by placing it in the first position of an expression:
((lambda (x) (* x x)) 5) ; → 25
This is equivalent to:
(defun square (x) (* x x))
(square 5) ; → 25
But the lambda version doesn't need a name — it is created and used in a single step.
Storing a lambda in a variable
You can also assign a lambda to a variable:
(setq square (lambda (x) (* x x)))
However, be aware that in AutoLISP, to call a function stored in a variable, you will need to use apply (which we will see next).
Higher-order functions
A higher-order function is a function that takes another function as an argument. This is one of the most powerful concepts in functional programming, and AutoLISP provides several of them.
mapcar: applying a function to each element
mapcar applies a function to each element of one or more lists and returns a list of the results:
(mapcar '1+ '(1 2 3 4 5))
; → (2 3 4 5 6) — adds 1 to each element

With a lambda function:
(mapcar '(lambda (x) (* x x)) '(1 2 3 4 5))
; → (1 4 9 16 25) — computes the square of each element
mapcar with multiple lists (elements are taken in parallel):
(mapcar '+ '(1 2 3) '(10 20 30))
; → (11 22 33) — adds elements pairwise
apply: applying a function to a list of arguments
apply takes a function and a list, and calls the function with the list elements as arguments:
(apply '+ '(1 2 3 4 5)) ; → 15 — equivalent to (+ 1 2 3 4 5)
(apply 'max '(3 7 1 9 2)) ; → 9 — equivalent to (max 3 7 1 9 2)
(apply 'strcat '("Hel" "lo")) ; → "Hello"
This is very useful when you have a list of values and want to pass them as individual arguments to a function.
vl-sort: sorting a list
vl-sort sorts a list using a comparison function:
(vl-sort '(3 1 4 1 5 9 2 6) '<)
; → (1 2 3 4 5 6 9) — ascending order (duplicates are removed)
(vl-sort '(3 1 4 1 5 9 2 6) '>)
; → (9 6 5 4 3 2 1) — descending order (duplicates are removed)
Warning:
vl-sortcan remove duplicates from the list. The official documentation states: "Duplicate elements may be eliminated from the list". This behavior is not guaranteed — it depends on the internal implementation — but in practice, duplicates are always removed. If you need to preserve duplicates, sort the indices of the list instead and reconstruct it afterward.
With a lambda for custom sorting:
;; Sort strings by length
(vl-sort '("cat" "hippopotamus" "rat" "dog")
'(lambda (a b) (< (strlen a) (strlen b)))
)
; → ("rat" "cat" "dog" "hippopotamus")
vl-remove-if and vl-remove-if-not: filtering
;; Keep only even numbers
(vl-remove-if-not
'(lambda (x) (= (rem x 2) 0))
'(1 2 3 4 5 6 7 8 9 10)
)
; → (2 4 6 8 10)
;; Remove negative numbers
(vl-remove-if
'(lambda (x) (< x 0))
'(-3 5 -1 8 -7 2)
)
; → (5 8 2)
Practical example: transforming points
Imagine we have a list of 2D points and we want to move them by 100 units in X and 50 in Y:
(setq points '((0 0) (10 20) (30 40) (50 60)))
(setq translated-points
(mapcar
'(lambda (point)
(list
(+ (car point) 100)
(+ (cadr point) 50)
)
)
points
)
)
; → ((100 50) (110 70) (130 90) (150 110))
Let's compare with a classic imperative approach:
;; Loop version
(setq translated-points '())
(foreach point points
(setq translated-points
(append translated-points
(list
(list
(+ (car point) 100)
(+ (cadr point) 50)
)
)
)
)
)
The mapcar version is more concise and more readable once you are familiar with these concepts.
Summary
| Concept | Syntax | Description |
|---|---|---|
| Quoting | 'x or (quote x) |
Prevents evaluation |
| Evaluation | (eval expr) |
Forces evaluation |
| Lambda | (lambda (args) body) |
Anonymous function |
mapcar |
(mapcar 'fn lst) |
Applies a function to each element |
apply |
(apply 'fn lst) |
Calls a function with a list of arguments |
vl-sort |
(vl-sort lst 'fn) |
Sorts a list |
vl-remove-if |
(vl-remove-if 'fn lst) |
Filters out elements |
vl-remove-if-not |
(vl-remove-if-not 'fn lst) |
Keeps matching elements |
In the next chapter, we will see how to attach custom data to entities and link entities together through their handles.
Need an AutoCAD (AutoLISP, ObjectARX, .NET, VBA) development? Contact me for a free quote.