Replace example blocks with src

This commit is contained in:
Marcus Kammer 2024-05-01 10:35:01 +02:00
parent f960388d0f
commit df0b737523
Signed by: marcuskammer
GPG key ID: C374817BE285268F

View file

@ -755,9 +755,9 @@ three parts: the symbol lambda, a parameter list, and a body of zero or
more expressions. This lambda-expression refers to a function equivalent more expressions. This lambda-expression refers to a function equivalent
to double: to double:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(lambda (x) (* x 2)) (lambda (x) (* x 2))
#+END_EXAMPLE #+END_SRC
It describes a function which takes one argument x, and returns 2x. It describes a function which takes one argument x, and returns 2x.
@ -842,12 +842,12 @@ Beneath the surface, defun is setting the symbol-function of its first
argument to a function constructed from the remaining arguments. The argument to a function constructed from the remaining arguments. The
following two expressions do approximately the same thing: following two expressions do approximately the same thing:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun double (x) (* x 2)) (defun double (x) (* x 2))
(setf (symbol-function 'double) (setf (symbol-function 'double)
#'(lambda (x) (* x 2))) #'(lambda (x) (* x 2)))
#+END_EXAMPLE #+END_SRC
So defun has the same effect as procedure definition in other So defun has the same effect as procedure definition in other
languages--to associate a name with a piece of code. But the underlying languages--to associate a name with a piece of code. But the underlying
@ -875,28 +875,28 @@ way of calling them. In Lisp, this function is apply. Generally, we call
apply with two arguments: a function, and a list of arguments for it. apply with two arguments: a function, and a list of arguments for it.
The following four expressions all have the same effect: The following four expressions all have the same effect:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(+ 1 2) (+ 1 2)
(apply #'+ '(1 2)) (apply #'+ '(1 2))
(apply (symbol-function '+) '(1 2)) (apply (symbol-function '+) '(1 2))
(apply #'(lambda (x y) (+ x y)) '(1 2)) (apply #'(lambda (x y) (+ x y)) '(1 2))
#+END_EXAMPLE #+END_SRC
In Common Lisp, apply can take any number of arguments, and the function In Common Lisp, apply can take any number of arguments, and the function
given first will be applied to the list made by consing the rest of the given first will be applied to the list made by consing the rest of the
arguments onto the list given last. So the expression arguments onto the list given last. So the expression
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(apply #'+ 1 '(2)) (apply #'+ 1 '(2))
#+END_EXAMPLE #+END_SRC
is equivalent to the preceding four. If it is inconvenient to give the is equivalent to the preceding four. If it is inconvenient to give the
arguments as a list, we can use funcall, which differs from apply only arguments as a list, we can use funcall, which differs from apply only
in this respect. This expression in this respect. This expression
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(funcall #'+ 1 2) (funcall #'+ 1 2)
#+END_EXAMPLE #+END_SRC
has the same effect as those above. has the same effect as those above.
@ -957,14 +957,14 @@ the elements of the list for which the function returns false.
As an example of a function which takes functional arguments, here is a As an example of a function which takes functional arguments, here is a
definition of a limited version of remove-if: definition of a limited version of remove-if:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun our-remove-if (fn lst) (defun our-remove-if (fn lst)
(if (null lst) (if (null lst)
nil nil
(if (funcall fn (car lst)) (if (funcall fn (car lst))
(our-remove-if fn (cdr lst)) (our-remove-if fn (cdr lst))
(cons (car lst) (our-remove-if fn (cdr lst)))))) (cons (car lst) (our-remove-if fn (cdr lst))))))
#+END_EXAMPLE #+END_SRC
Note that within this definition fn is not sharp-quoted. Since functions Note that within this definition fn is not sharp-quoted. Since functions
are data objects, a variable can have a function as its regular value. are data objects, a variable can have a function as its regular value.
@ -992,7 +992,7 @@ Suppose we want to write a function which takes a type of animal and
behaves appropriately. In most languages, the way to do this would be behaves appropriately. In most languages, the way to do this would be
with a case statement, and we can do it this way in Lisp as well: with a case statement, and we can do it this way in Lisp as well:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun behave (animal) (defun behave (animal)
(case animal (case animal
(dog (wag-tail) (dog (wag-tail)
@ -1001,25 +1001,25 @@ with a case statement, and we can do it this way in Lisp as well:
(squeak)) (squeak))
(cat (rub-legs) (cat (rub-legs)
(scratch-carpet)))) (scratch-carpet))))
#+END_EXAMPLE #+END_SRC
What if we want to add a new type of animal? If we were planning to add What if we want to add a new type of animal? If we were planning to add
new animals, it would have been better to define behave as follows: new animals, it would have been better to define behave as follows:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun behave (animal) (defun behave (animal)
(funcall (get animal 'behavior))) (funcall (get animal 'behavior)))
#+END_EXAMPLE #+END_SRC
and to define the behavior of an individual animal as a function stored, and to define the behavior of an individual animal as a function stored,
for example, on the property list of its name: for example, on the property list of its name:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(setf (get 'dog 'behavior) (setf (get 'dog 'behavior)
#'(lambda () #'(lambda ()
(wag-tail) (wag-tail)
(bark))) (bark)))
#+END_EXAMPLE #+END_SRC
This way, all we need do in order to add a new animal is define a new This way, all we need do in order to add a new animal is define a new
property. No functions have to be rewritten. property. No functions have to be rewritten.
@ -1062,11 +1062,11 @@ as a parameter, or by variable-binding operators like let and do.
Symbols which are not bound are said to be free. In this example, scope Symbols which are not bound are said to be free. In this example, scope
comes into play: comes into play:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(let ((y 7)) (let ((y 7))
(defun scope-test (x) (defun scope-test (x)
(list x y))) (list x y)))
#+END_EXAMPLE #+END_SRC
Within the defun expression,x is bound and y is free. Free variables are Within the defun expression,x is bound and y is free. Free variables are
interesting because it's not obvious what their values should be. interesting because it's not obvious what their values should be.
@ -1135,11 +1135,11 @@ closures. For example, suppose we want to write a function which takes a
list of numbers and adds a certain amount to each one. The function list of numbers and adds a certain amount to each one. The function
list+ list+
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun list+ (lst n) (defun list+ (lst n)
(mapcar #'(lambda (x) (+ x n)) (mapcar #'(lambda (x) (+ x n))
lst)) lst))
#+END_EXAMPLE #+END_SRC
will do what we want: will do what we want:
@ -1159,11 +1159,11 @@ by Abelson and Sussman's classic Structure and Interpretation of
Computer Programs. Closures are functions with local state. The simplest Computer Programs. Closures are functions with local state. The simplest
way to use this state is in a situation like the following: way to use this state is in a situation like the following:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(let ((counter 0)) (let ((counter 0))
(defun new-id () (incf counter)) (defun new-id () (incf counter))
(defun reset-id () (setq counter 0))) (defun reset-id () (setq counter 0)))
#+END_EXAMPLE #+END_SRC
These two functions share a variable which serves as a counter. The These two functions share a variable which serves as a counter. The
first one returns successive values of the counter, and the second first one returns successive values of the counter, and the second
@ -1174,10 +1174,10 @@ references.
It's also useful to be able to return functions with local state. For It's also useful to be able to return functions with local state. For
example, the function make-adder example, the function make-adder
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun make-adder (n) (defun make-adder (n)
#'(lambda (x) (+ x n))) #'(lambda (x) (+ x n)))
#+END_EXAMPLE #+END_SRC
takes a number, and returns a closure which, when called, adds that takes a number, and returns a closure which, when called, adds that
number to its argument. We can make as many instances of adders as we number to its argument. We can make as many instances of adders as we
@ -1197,13 +1197,13 @@ In the closures returned by make-adder, the internal state is fixed, but
it's also possible to make closures which can be asked to change their it's also possible to make closures which can be asked to change their
state. state.
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun make-adderb (n) (defun make-adderb (n)
#'(lambda (x &optional change) #'(lambda (x &optional change)
(if change (if change
(setq n x) (setq n x)
(+ x n)))) (+ x n))))
#+END_EXAMPLE #+END_SRC
This new version of make-adder returns closures which, when called with This new version of make-adder returns closures which, when called with
one argument, behave just like the old ones. one argument, behave just like the old ones.
@ -1241,7 +1241,7 @@ closed over their own shared copy of an assoc-list.
#<Interpreted-Function 802347>) #<Interpreted-Function 802347>)
#+END_EXAMPLE #+END_EXAMPLE
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun make-dbms (db) (defun make-dbms (db)
(list (list
#'(lambda (key) #'(lambda (key)
@ -1252,7 +1252,7 @@ closed over their own shared copy of an assoc-list.
#'(lambda (key) #'(lambda (key)
(setf db (delete key db :key #'car)) (setf db (delete key db :key #'car))
key))) key)))
#+END_EXAMPLE #+END_SRC
Figure 2.1: Three closures share a list. Figure 2.1: Three closures share a list.
@ -1274,10 +1274,10 @@ Calling the car of a list is a bit ugly. In real programs, the access
functions might instead be entries in a structure. Using them could also functions might instead be entries in a structure. Using them could also
be cleaner--databases could be reached indirectly via functions like: be cleaner--databases could be reached indirectly via functions like:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun lookup (key db) (defun lookup (key db)
(funcall (car db) key)) (funcall (car db) key))
#+END_EXAMPLE #+END_SRC
However, the basic behavior of closures is independent of such However, the basic behavior of closures is independent of such
refinements. refinements.
@ -1330,11 +1330,11 @@ But now suppose that the function has to be a closure, taking some
bindings from the environment in which the mapcar occurs. In our example bindings from the environment in which the mapcar occurs. In our example
list+, list+,
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun list+ (lst n) (defun list+ (lst n)
(mapcar #'(lambda (x) (+ x n)) (mapcar #'(lambda (x) (+ x n))
lst)) lst))
#+END_EXAMPLE #+END_SRC
the first argument to mapcar,#'(lambda (x) (+ x n)), must be defined the first argument to mapcar,#'(lambda (x) (+ x n)), must be defined
within list+ because it needs to catch the binding of n. So far so good, within list+ because it needs to catch the binding of n. So far so good,
@ -1372,10 +1372,10 @@ However, there is an important difference between let and labels. In a
let expression, the value of one variable can't depend on another let expression, the value of one variable can't depend on another
variable made by the same let--that is, you can't say variable made by the same let--that is, you can't say
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(let ((x 10) (y x)) (let ((x 10) (y x))
y) y)
#+END_EXAMPLE #+END_SRC
and expect the value of the new y to reflect that of the new x. In and expect the value of the new y to reflect that of the new x. In
contrast, the body of a function f defined in a labels expression may contrast, the body of a function f defined in a labels expression may
@ -1385,7 +1385,7 @@ makes recursive function definitions possible.
Using labels we can write a function analogous to list+, but in which Using labels we can write a function analogous to list+, but in which
the first argument to mapcar is a recursive function: the first argument to mapcar is a recursive function:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun count-instances (obj lsts) (defun count-instances (obj lsts)
(labels ((instances-in (lst) (labels ((instances-in (lst)
(if (consp lst) (if (consp lst)
@ -1393,7 +1393,7 @@ the first argument to mapcar is a recursive function:
(instances-in (cdr lst))) (instances-in (cdr lst)))
0))) 0)))
(mapcar #'instances-in lsts))) (mapcar #'instances-in lsts)))
#+END_EXAMPLE #+END_SRC
This function takes an object and a list, and returns a list of the This function takes an object and a list, and returns a list of the
number of occurrences of the object in each element: number of occurrences of the object in each element:
@ -1414,22 +1414,22 @@ A recursive function is one that calls itself. Such a call is
tail-recursive if no work remains to be done in the calling function tail-recursive if no work remains to be done in the calling function
afterwards. This function is not tail-recursive afterwards. This function is not tail-recursive
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun our-length (lst) (defun our-length (lst)
(if (null lst) (if (null lst)
0 0
(1+ (our-length (cdr lst))))) (1+ (our-length (cdr lst)))))
#+END_EXAMPLE #+END_SRC
because on returning from the recursive call we have to pass the result because on returning from the recursive call we have to pass the result
to 1+. The following function is tail-recursive, though to 1+. The following function is tail-recursive, though
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun our-find-if (fn lst) (defun our-find-if (fn lst)
(if (funcall fn (car lst)) (if (funcall fn (car lst))
(car lst) (car lst)
(our-find-if fn (cdr lst)))) (our-find-if fn (cdr lst))))
#+END_EXAMPLE #+END_SRC
because the value of the recursive call is immediately returned. because the value of the recursive call is immediately returned.
@ -1445,14 +1445,14 @@ that is by embedding in it a local function which uses an accumulator.
In this context, an accumulator is a parameter representing the value In this context, an accumulator is a parameter representing the value
computed so far. For example, our-length could be transformed into computed so far. For example, our-length could be transformed into
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun our-length (lst) (defun our-length (lst)
(labels ((rec (lst acc) (labels ((rec (lst acc)
(if (null lst) (if (null lst)
acc acc
(rec (cdr lst) (1+ acc))))) (rec (cdr lst) (1+ acc)))))
(rec lst 0))) (rec lst 0)))
#+END_EXAMPLE #+END_SRC
where the number of list elements seen so far is contained in a second where the number of list elements seen so far is contained in a second
parameter, acc. When the recursion reaches the end of the list, the parameter, acc. When the recursion reaches the end of the list, the
@ -1464,9 +1464,9 @@ Many Common Lisp compilers can do tail-recursion optimization, but not
all of them do it by default. So after writing your functions to be all of them do it by default. So after writing your functions to be
tail-recursive, you may also want to put tail-recursive, you may also want to put
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(proclaim '(optimize speed)) (proclaim '(optimize speed))
#+END_EXAMPLE #+END_SRC
at the top of the file, to ensure that the compiler can take advantage at the top of the file, to ensure that the compiler can take advantage
of your efforts.[fn:4] of your efforts.[fn:4]
@ -1476,7 +1476,7 @@ compilers can generate code that runs as fast as, or faster than, C.
Richard Gabriel gives as an example the following function, which Richard Gabriel gives as an example the following function, which
returns the sum of the integers from 1 to n: returns the sum of the integers from 1 to n:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun triangle (n) (defun triangle (n)
(labels ((tri (c n) (labels ((tri (c n)
(declare (type fixnum n c)) (declare (type fixnum n c))
@ -1485,7 +1485,7 @@ returns the sum of the integers from 1 to n:
(tri (the fixnum (+ n c)) (tri (the fixnum (+ n c))
(the fixnum (- n 1)))))) (the fixnum (- n 1))))))
(tri 0 n))) (tri 0 n)))
#+END_EXAMPLE #+END_SRC
This is what fast Common Lisp code looks like. At first it may not seem This is what fast Common Lisp code looks like. At first it may not seem
natural to write functions this way. It's often a good idea to begin by natural to write functions this way. It's often a good idea to begin by
@ -1612,32 +1612,32 @@ If we have a particularly small function, we may want to request that it
be compiled inline. Otherwise, the machinery of calling it could entail be compiled inline. Otherwise, the machinery of calling it could entail
more effort than the function itself. If we define a function: more effort than the function itself. If we define a function:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun 50th (lst) (nth 49 lst)) (defun 50th (lst) (nth 49 lst))
#+END_EXAMPLE #+END_SRC
and make the declaration: and make the declaration:
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(proclaim '(inline 50th)) (proclaim '(inline 50th))
#+END_EXAMPLE #+END_SRC
then a reference to 50th within a compiled function should no longer then a reference to 50th within a compiled function should no longer
require a real function call. If we define and compile a function which require a real function call. If we define and compile a function which
calls 50th, calls 50th,
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun foo (lst) (defun foo (lst)
(+ (50th lst) 1)) (+ (50th lst) 1))
#+END_EXAMPLE #+END_SRC
then when foo is compiled, the code for 50th should be compiled right then when foo is compiled, the code for 50th should be compiled right
into it, just as if we had written into it, just as if we had written
#+BEGIN_EXAMPLE #+BEGIN_SRC lisp
(defun foo (lst) (defun foo (lst)
(+ (nth 49 lst) 1)) (+ (nth 49 lst) 1))
#+END_EXAMPLE #+END_SRC
in the first place. The drawback is that if we redefine 50th, we also in the first place. The drawback is that if we redefine 50th, we also
have to recompile foo, or it will still reflect the old definition. The have to recompile foo, or it will still reflect the old definition. The