• Aucun résultat trouvé

DEFINING YOUR OWN FUNCTIONS

Dans le document COMMON LISP An Interactive Approach (Page 79-85)

Although there are quite a few functions provided by the Common Lisp system (some say that there are too many), you will want to define your own.

Indeed, a Lisp program is nothing but a collection of functions written by theLispprogrammer.

To define a function, you use the special formdefun:

(defun fn varlist doc-string form) fnmust be a symbol.

varlist must be an empty list or a list of symbols.

doc-stringmust be a string.

formcan be anyCommon Lispform.

None of these are evaluated. defunreturnsfn, but its main use is that it has the side effect of defining fnto be the name of a function whose formal arguments are the symbols in varlist, whose definition is form, and whose documentation string isdoc-string.

In Lisp terminology, we call the formal arguments of a function lambda variables. This has historical significance because of the influence of A.

Church’s Lambda Calculus in the design of Lisp. You may see the symbol lambdaas part of yourCommon Lisp’s printed representation of functions, but we will not discuss this in too much detail.

Let’s consider an example:

> (defun list3 (o1 o2 o3)

55

56 II: PROGRAMMING IN PURE LISP

"Returns a list of its three arguments in order."

(cons o1 (cons o2 (cons o3 ’())))) LIST3

This has the effect of defining the function list3, which takes three Lisp objects as arguments and returns a list whose members are those objects.

After evaluating this defun, we can use list3 just as if it were a built-in Lispfunction:

> (list3 ’a (cons ’b ’()) ’c) (A (B) C)

The documentation string provides documentation that can be retrieved from

the function name with the Common Lisp function

documentation:

> (documentation ’list3 ’function)

"Returns a list of its three arguments in order."

The choice of the symbolso1,o2, ando3for the lambda variables oflist3 is completely arbitrary. We could have chosen almost any three symbols, but nilandt, in particular, would have been very bad choices.

The steps in the evaluation of a list were summarized on page 49. Now that we have seen a programmer-defined function, we can give more details (almost allCommon Lisp functions are defined inLisp, so this really does apply to more than just programmer-defined functions).

When a function is called—that is, whenLispis asked to evaluate a list—

the following happens:

1. Lisp checks that the first member of the list is a symbol that is the name of a function.

2. The argument forms are evaluated (not necessarily left to right).

3. The values of the argument forms become the values of the correspond-ing lambda variables. (We say that the variables arebound tothe values of the arguments.)

4. The form in the definition of the function is evaluated.

5. The lambda variables are unbound—returned to their previous states.

6. The value of the form in the definition becomes the value of the original form.

Let us follow the evaluation of (list3 ’a (cons ’b ’()) ’c) through the process:

10: Defining Your Own Functions 57 1. list3is a symbol that is the name of a function.

2. ’aevaluates toA,(cons ’b ’())to(B), and’cto C.

3. o1is bound toA,o2to(B), ando3toC.

4. (cons o1 (cons o2 (cons o3 ’()))) is evaluated. Note that the symbols o1, o2, and o3have values during this evaluation. The value of this form is (A (B) C).

5. o1,o2, ando3return to their previous values (possibly none).

6. (A (B) C)is returned as the value of

(list3 ’a (cons ’b ’()) ’c)

This is the first time that we have seen a symbol get a new value. The primary method by which a symbol gets a value is to be bound as a lambda variable. We should not usetor nilas lambda variables because we always want them to have themselves as values.

For another example of a programmer-defined function, let’s define a func-tion to interchange the two members of a two-member list:

> (defun switch (l)

"Given a two-member list, returns a list just like it, but with the two members interchanged."

(list2 (second l) (first l))) SWITCH

In this definition, I’ve used a function namedlist2and one namedsecond even though I’ve never before said that such functions are available in Com-mon Lisp. This doesn’t matter, because we can use an undefined function in the definition of a function, as long as we define it before actually calling it. The functionslist2andsecondare just so obviously clear and useful in this context that it makes sense to defineswitchthis way and worry about defininglist2andsecondlater. It turns out thatsecondis already defined inCommon Lisp, butlist2isn’t; so let’s define it:

> (defun list2 (o1 o2)

"Returns a list of its two arguments in order."

(cons o1 (cons o2 ’()))) LIST2

We’ve now written a short program consisting of two functions, one of which uses the other. We must test this program. One of the beauties of Lispis that we can test programs “bottom up.” That is, it’s a good idea to

58 II: PROGRAMMING IN PURE LISP make sure thatlist2works properly before testingswitch, because iflist2 doesn’t work, then surelyswitch won’t either. In most other programming languages, it is easy to run a main program, but difficult to test a subprogram.

InLisp, any function can be tested directly from top-levelLisp, and any form that appears in a function definition may be evaluated directly by the top-level listener, as long as you replace each lambda variable in it (or each form that contains lambda variables) by sample values. So let’s testlist2:

> (list2 (second ’(a b)) (first ’(a b))) (B A)

> (list2 ’b ’a) (B A)

Now we can testswitch:

> (switch ’(a b)) (B A)

You could also do top-down testing, since the only effect of calling an un-defined function is to put you into the debugger. Some debuggers will provide an easy way to specify the value the function call would have returned, so you can simulate the undefined function, and go on testing the other func-tions. Other debuggers make this process a bit harder. In general, I advise bottom-up testing.

Exercises

10.1 (r)Define the function list3as given in this chapter, and test it on several different groups of arguments.

10.2 (r)Check the values of o1, o2, ando3 both before and after a call to list3. Notice that, even though they have values withinlist3, they have no values either before or after.

10.3 (i)Define switch as given in this chapter and try it out before defin-ing list2. The error occurs when Lisp tries to evaluate the form (list2 (second l) (first l)). You should now make sure you know how to find the value to which the lambda variable l is bound. The method differs among implementations of Common Lisp. It may be that the value ofl was printed as part of the error message. (This is the case on the Texas Instruments Explorer Lisp Machine.) Chances are

that you

cannot find out merely by typinglto the debugger listener, because of various efficiencies used byCommon Lispimplementations to store the values of lambda variables. However, there should be something you can

10: Defining Your Own Functions 59 type to yourLisp to make it tell you. For example, if you are using a Texas Instruments Explorer Lisp Machine, you can just read it in the

er-ror message or enter

(eh-arg 0). If you are using Kyoto Common Lisp, you enter :vv.

If it is not obvious, see if yourLisp has a help facility you can use in the debugger. If so, you will probably be told there. As a last resort, ask your instructor or a more experienced friend. After learning how to find the value of the lambda arguments, write the method here and in Appendix B.2:

. Get out of the debugger and back to the top-level listener.

10.4 (r)Now definelist2, testlist2, and testswitchagain.

10.5 (i)You can observeLispevaluating a set of functions by using the trace package. This consists of the two special forms trace and untrace.

(trace fn1. . . fnk) turns on the tracing of functions fn1, . . . , fnk. (untrace fn1. . . fnk)turns them off. Evaluate(trace switch first

second list2) and (switch ’(a b)).

Note that when each function is called, its arguments are printed and when it returns, its value is printed. Also note that each trace print is labelled and/or indented so you can tell which value goes with which call. Now evaluate

(untrace switch first second list2) and(switch ’(a b))again. The tracing has been turned off.

10.6 (i)Try givingswitchargument lists with fewer than two members and with more than two members. Make sure you understand why the values are what they are. Peculiar results are acceptable when the argument forms do not satisfy the conditions spelled out in the documentation string, but we will see later how we can getLispto test these conditions for us.

10.7 (d)Redefinelist3usinglist2andcons.

10.8 (d)Define the functionlist1to be a function that takes one argument and returns a list with the value of that argument as its only member.

10.9 (d)Redefinelist2usinglist1andcons.

10.10 (d) Test list3 while tracing list1, list2, and list3. Notice that although you didn’t redefine list3, it now uses your new version of list2.

60 II: PROGRAMMING IN PURE LISP 10.11 (d)Define the functionslist4throughlist10, each taking the obvious number of arguments and returning a list of their values. Each definition need be no longer than your current definition oflist2. Use the tracing facility to watch some of these in action.

10.12 (i) The Common Lisp function list takes an arbitrary number of arguments and returns a list of all of them. Try this function with various numbers of arguments.

10.13 (d)Redefineswitch to uselist, and test this version.

10.14 (d)Define the function(sqr n)to return the square of the numbern.

10.15 (i)Common Lisphas the functionthird, which takes a list and returns the third member of it. Try this out.

10.16 (d)Usingfirst,second,third, andlist, define the function(reverse3 l) to return the reverse of the three-member list, l. For example, (reverse3 ’(a b c))should evaluate to(C B A).

10.17 (i)You now know thatCommon Lisphas the functionsfirst,second, andthird. How many functions in this sequence are defined?

CHAPTER 11

DEFINING FUNCTIONS IN

Dans le document COMMON LISP An Interactive Approach (Page 79-85)