Programming Course |
Chapter 3Functional Programming Lisp II - Basic Functions |
The basic unit of evaluation in LISP is an expression. An expression is a sentence in Lisp and it can be a value, a symbol, or a list. It is the basic unit which the LISP interpreter evaluates in one step.
Every LISP expression that you enter from the keyboard is evaluated, and the result of the evaluation process is returned. The AutoLisp environment also has a LISP interpreter - sometimes called an evaluator, and it works as follows:
Although this process may look complicated, it is possible to define an interpreter for the LISP language in LISP itself!
A list may be made up of zero of more atoms, for example: (3 2.6 -8.9). If we want to access or change any of the atoms in the list, two LISP operations are provided.
(car a_list) This operation returns the first element of an argument list.
(cdr a_list) This operation returns a list of everything in an argument list except its first element.
Examples: Evaluate the following expressions exactly as shown, including the quote (') character before the lists.
(car '(a b c)) => A
(cdr '(a b c)) => (B C)
(car '((3 b) c)) =>
(cdr '((3 b) c)) =>
(cdr '(a)) =>
What happens if you evaluate the following expressions?
(setq a_list '((23.9 ab)(apples oranges cherries)(dogs
cats cows)))
=>
(car (car a_list)) =>
(cdr (cdr a_list)) =>
(car (cdr a_list))=>
(cdr (car a_list))=>
When a number of list operations involving => and cdr are needed, it is possible to combine them into compound operations by joining a (from car) and d (from cdr) between the letters c and r. For example, the previous four examples could be rewritten as follows:
(caar a_list) =>
(cddr a_list) =>
(cadr a_list) =>
(cdar a_list) =>
In order to insert new symbols into a list, the following operations are available in LISP.
(list a_sym b_sym ...)
Returns a new list formed by putting all the arguments into one
big list.
(list 'a 'b) => (A B)
(cons new_sym a_list)
Returns a new list formed by inserting the first argument at the
head of the second argument list. The first argument can be an
atom or a list.
(cons 'a '(b c)) => (A B C)
(append a_list b_list)
Returns a new list formed by inserting all arguments together
into a new list. Arguments need to be lists.
(append '(a b) '(c d)) => (A B C D)
Examples: Enter the following expressions exactly as shown.
(not (< 0 1.5)) => nil
(not (= 2.5 3.5)) => T
(and (< 2 3 5) (/= 0 1)) =>
(and (< 3 2 4) (/ 1 1.9)) =>
(or (> 2 3 4) (/= 3.5 6.5)) =>
(or (> 2 3 4) (= "ab" "AB")) =>
(list 'a '(b c) 3 '(a 3.9)) =>
(setq f1 '(a b c)) =>
(setq f2 '(d e f)) =>
(cons 3.5 f1) =>
!f1 =>
(append f1 f2) =>
!f1 =>
!f2 =>
(setq f1 (cons 3.5 f1)) =>
!f1 =>
(setq f2 (append f1 f2)) =>
!f2 =>
!f1 =>
LISP distinguishes between functions and special forms. Normally, when a LISP expression is evaluated by the LISP interpreter, every component of this expression, whether atom or list, is evaluated as part of the evaluation process. Special forms differ from this rule in that one or more components of the expression are not evaluated.
LISP expressions are always immediately evaluated by the LISP interpreter, unless the evaluation of the expression is explicitly blocked by the user. quote is a predefined LISP function that delays evaluation.
(quote expr) quote is a special form, it is an evaluation blocker and returns expr without any evaluation.
´expr A quote character followed by expr is an abbreviation of (quote expr).
Unless a list is preceded by a quote ('), the LISP interpreter will attempt to evaluate the list assuming the first argument is or defines a function. Examples:
(setq a (+ 2 3)) => 5
(setq a '(+ 2 3)) =>
(setq b 'a) =>
Sometimes it may be necessary to force the LISP interpreter to evaluate an expression, for example if evaluation of the expression was blocked earlier with a quote.
(eval expr) eval is a function, it applies an extra evaluation to expr and returns the result.
(eval 2) => 2
(eval ´(+ 1 2)) =>
(setq a 2) => 2
(eval ´a) =>
(eval (eval ´a)) =>
(eval ´(+ a 4)) =>
(eval (list ´+ ´a 4)) =>
(setq symbol expr)
setq is
a special form. The first argument should be a symbol which will
not be evaluated and is assigned with the value of the second
argument.
(set expr1 expr2)
set is
a function. The value of the second argument is assigned to the
result of the evaluation of the first argument.
(setq a ´b) => B
(set a 3) =>
!a =>
!b =>
(apply func list)
apply is
a function. It applies a function to the list
and returns the result of the application.
(apply ´+ ´(1 2 3 4)) => 10
(apply ´* ´(1 2 3 4)) =>
(apply ´max ´(2 4 3 8)) =>
(defun average (alist)
(/ (apply ´+ alist) (length alist))
) => AVERAGE
(average ´(2 4 6 8)) =>
All the examples introduced so far use predefined operations in LISP, e.g., car, cdr, +, *, minusp, zerop, etc. These are defined as functions made up of nothing but LISP expressions. LISP also allows you to define your own functions.
To define your own functions in LISP which you can reuse again and again, the following form should be used.
(defun function_name arguments
expression_1
expression_2
...
)
function_name is written in italics to indicate that any symbol (usually a name suggesting what a function does) can be used, arguments can be any list of symbols, i.e., the argument names, even an empty list. The rest of the form are one or more valid LISP expressions, including AutoCAD commands. The meaning of the arguments is explained below.
Example: For the following example, you should open a Jot window and enter the following text. Save the file as test.lsp and then load it into AutoCAD by entering at the command prompt: (load "test")
(defun test_function ()
(setq a 2.0)
(setq b 3.0)
(setq c '(This is a list))
(princ "Square of variable a: ")
(princ (* a a))
(princ "\n")
(princ "Cube of variable b: ")
(princ (* b b b))
(princ "\n")
(princ "Value of variable c: ")
(princ c)
(princ "\n")
(setq d "this is a string!")
(princ d)
(princ)
)
The empty list after the function name test_function means that this function has no arguments. If the file is successfully loaded, the LISP interpreter will return the atom test_function. Now you can use it just like any other predefined LISP operation. Since this function takes no arguments, simply enter the function name to evaluate it:
(test_function)
The usefulness of a function without any arguments is rather limited, as it will give the exact same result every time it is evaluated. The following function square illustrates the use of arguments in functions. It takes a single argument x and returns the square of the value of x.
(defun square (x)
(* x x)
)
(square 4) => 16
What is a lambda expression?
A lambda expression has a list of parameters, and a body which consists of a sequence of expressions. The list of parameters defines the environment in which the expressions are to be evaluated. Lambda calculus, introduced by Alonzo Church in 1941, led to the development of LISP and functional programming. A lambda expression, explained below, is similar to the defun construct above. It is useful when you need to use a procedure in only one or a very few places in a program and you do not want to define a special procedure by a unique name.
(lambda args expr....)
lambda is a special form. None of its arguments
are evaluated. It returns a lambda expression which can be applied
to a number of arguments.
(defun name args expr...)
defun is a special form. None of its arguments
are evaluated. It assigns a lambda expression to its first argument.
(defun a (x)(+ x x)) is equivalent to (setq a (lambda (x)(+ x x))) in AutoLisp.
This exercise gives you an opportunity to define your own functions. Each of the required functions draws some elements on the screen. You have to figure out how and where coordinate values will need to be changed so that each function generates elements in different parts of the screen (i.e. your drawing). The following three LISP functions are required:
Besides realizing that AutoCAD commands are valid
LISP expressions that can be used as part of functions, you will
also see what the differences are between polylines, solid faces,
and real solid volumes!