defun
instead
of define
. The major difference in syntax is that in Lisp
the formal arguments are written in parentheses while the function name os
not.
Here are some examples from the textbook:
(defun sum-greater (x y z) (> (+ x y) z)) (defun our-length (lst) (let ((len 0)) ;; notice the use of the function dolist (dolist (obj lst) (incf len)) len)) ;;; same as above written using recursion. Less efficient but perfectly fine (defun our-length (lst) (if (null lst) 0 (+ (our-length (cdr lst)) 1)))
Lisp | Scheme |
consp | pair? |
listp | list? |
eq | eq? |
equal | equal? |
null | null? |
mapcar | map |
mapc | for-each |
progn | begin |
setf | set-car! |
setf | set-cdr! |
(eq object1 object2)
Two objects are eq if they have the same location in memory. This
works for symbols, not for numbers and characters.
(eql object1 object2)
this is the most widely used equality predicate. It is true if
the two objects are eq, but also if they are the same character or
two numbers that look the same when printed.
When both elements are integers, (= object1 object2)
will also work.
(equal object1 object2)
this is used to compare objects that have cons boxes (such as lists),
strings, bit-vectors, and path-names. Of course, objects that are
eql are also equal.
(equalp object1 object2)
this is the most general predicate, and works also for arrays,
structures, hash-tables.
setf
is a very general function for assignments.
(setf < place> < value>)is used to assign a new value to a place. A place can be a variable, or a function call whose first element is
car
or cdr
, or most combinations of
car
and cdr
. For instance,
(setf (car lst) 'a)is equivalent to the Scheme expression
(set-car! lst 'a)
defvar
,
defparameter
, defconstant
, or, more commonly,
setf
, on which more is said later.
The common convention is to use a * around the names
of any global variable, as in *counter*
, to make it easier to
see that it is a global variable.
&optional
,
auxiliary parameters (using &aux
),
keywords (using &key
),
and a variable number of parameters (using &rest
).
These parameters can be initialized by replacing the parameters name
with a list (parameter initvalue)
.
&aux
allows to define local parameters in the list of
parameters, instead of defining them with let. It makes the code
shorter and easier to read. Look for examples in
mapping.
&key
allows to specify keywords. keywords parameters
can have default values and be passed in any order.
If a function includes keywords, the keywords are passed when the function
is called by specifying what is the keyword.
Many system defined functions use keywords to make them more flexible.
For instance:
;; see if d is a member of the car of each element in the list (member 'd '((a . 2) (d . 4) (c . 1)) :key #'car) = ((D . 4) (C . 1)) ;; uses equal for the equality test instead of eql (member '(d . 4) '((a . 2) (d . 4) (c . 1)) :test #'equal) = ((D . 4) (C . 1)) (member '(d . 5) '((a . 2) (d . 4) (c . 1)) :test-not #'equal) = ((A . 2) (D . 4) (C . 1))
&rest
binds all the remaining arguments as a list to the
&rest
parameter. Example:
(defun num-of-args (&rest lst) (length lst)) (num-of-args 'a 'b 'c 'd) = 4 (num-of-args 'a '(b c)) = 2 (num-of-args) = 0
car
and cdr
of an empty list. The value is nil
.
;; list here is a parameter (defun print-squares (list) ;; list here is again a parameter (dolist (element list) ;; but here it is a function (print (list element (expt element 2)))))Default choice of the namespace. When Lisp is given a list as a form to evaluate, if the first symbol in the list is not a special form or a macro. Lisp assumes it is the name of a function, and, consequently, uses its value in the functional namespace. For everything else Lisp uses the regular value.
Exceptions to the default choice of the namespace. Whenever the default choice of namespace is not appropriate we need to tell Lisp to select the other namespace. We do it in the following way:
(function < fn>)
, which is commonly
abbreviated as #'
This is typically used in a function call when a function is passed as
an argument to another function.
funcall
to specify
that the value of the symbol has to be used as a function and to pass its
appropriate argument(s). To be more precise, we will write
(funcall < fn> &rest < arguments>)
whenever
we want to use
the functional value of < fn>
and apply it to its arguments.
This typically happens in the body a function that takes a function as
an argument.
(defun filter (fn l) (cond ((null l) nil) ((funcall fn (car l)) (cons (car l) (filter fn (cdr l)))) (t (filter fn (cdr l)))))
funcall
is needed since fn
is not the function
we want to apply but the name of the function we want to apply.Example: (filter #'oddp '(1 4 3 8 9)) = (1 3 9)When
filter
is called we need to use #'
to
specify that we want the functional value of the symbol oddp
.
So, to repeat briefly how to select a namespace which it not the one used by default:
funcall
,
as in (funcall fn &rest arguments)
, for the symbol
fn
.
(function fn)
, which is commonly
abbreviated as #'
.
(symbol-function 'foo)
returns the current global function definition of foo
.
This signals an error if there is no functional value. The predicate
(fboundp 'foo)
can be used to check if foo
is the name of a global function.
(symbol-value 'foo)
returns the current value of the special variable foo
This signals an error if there is no value. The predicate
(boundp 'foo)
can be used to check if foo
is the name of a special variable.
(symbol-name 'foo)
returns the string that is the name of the symbol. This string cannot be
modified
(symbol-plist 'foo)
returns the property list of the symbol
special
have indefinite scope. Constants have also indefinite scope.
special
variable; the connection
to a file established by with-open-file
.
;;; USING THE LEXICAL SCOPE AND INDEFINITE EXTENT TO CREATE A VARIABLE ;;; THAT BEHAVES LIKE A GLOBAL VARIABLE BUT CAN BE ACCESSED ONLY IN A ;;; CONTROLLED WAY ;;; this create a local variable, counter, whichis shared by a group ;;; of functions. ;;; This allows multiple functions to operate on the same variable which ;;; is protected from any other access ;;; If multiple counters are needed it is better to use a generator ;;; (see the page on generators) (let ((counter 0)) ;; incf increments counter by 1 (defun bump-up () (incf counter)) (defun bump-down () (decf counter)) (defun counter-value () counter)) (bump-up) (bump-up) (counter-value)