meval-fascicule.lisp (44314B)
1 #| 2 Exo 4.1 Vérifier ce que fait la fonction "error" dans le poly ou le manuel en ligne. 3 4 24.1. General Error-Signaling Functions (beginning only) 5 The functions in this section provide various mechanisms for signaling warnings, breaks, 6 continuable errors, and fatal errors. 7 8 In each case, the caller specifies an error message (a string) that may be processed (and 9 perhaps displayed to the user) by the error-handling mechanism. All messages are constructed 10 by applying the function format to the quantities nil, format-string, and all the args to produce 11 a string. 12 13 An error message string should not contain a newline character at either the beginning or end, 14 and should not contain any sort of herald indicating that it is an error. The system will take care 15 of these according to whatever its preferred style may be. 16 17 Conventionally, error messages are complete English sentences ending with a period. 18 Newlines in the middle of long messages are acceptable. There should be no indentation after 19 a newline in the middle of an error message. The error message need not mention the name of the 20 function that signals the error; it is assumed that the debugger will make this information available. 21 22 Implementation note: If the debugger in a particular implementation displays error messages 23 indented from the prevailing left margin (for example, indented by seven spaces because they 24 are prefixed by the seven-character herald ``Error: ''), then the debugger should take care of 25 inserting the appropriate indentation into a multi-line error message. Similarly, a debugger that 26 prefixes error messages with semicolons so that they appear to be comments should take care of 27 inserting a semicolon at the beginning of each line in a multi-line error message. These rules 28 are suggested because, even within a single implementation, there may be more than one program 29 that presents error messages to the user, and they may use different styles of presentation. 30 The caller of error cannot anticipate all such possible styles, and so it is incumbent upon the 31 presenter of the message to make any necessary adjustments. 32 33 Common Lisp does not specify the manner in which error messages and other messages are displayed. 34 For the purposes of exposition, a fairly simple style of textual presentation will be used in the 35 examples in this chapter. The character > is used to represent the command prompt symbol for a debugger. 36 37 38 [Function] 39 error format-string &rest args 40 41 This function signals a fatal error. It is impossible to continue from this kind of error; 42 thus error will never return to its caller. 43 44 The debugger printout in the following example is typical of what an implementation might print when 45 error is called. Suppose that the (misspelled) symbol emergnecy-shutdown has no property named command 46 (all too likely, as it is probably a typographical error for emergency-shutdown). 47 48 (defun command-dispatch (cmd) 49 (let ((fn (get cmd 'command))) 50 (if (not (null fn)) 51 (funcall fn)) 52 (error "The command ~S is unrecognized." cmd)))) 53 54 (command-dispatch 'emergnecy-shutdown) 55 Error: The command EMERGNECY-SHUTDOWN is unrecognized. 56 Error signaled by function COMMAND-DISPATCH. 57 > 58 59 60 Compatibility note: Lisp Machine Lisp calls this function ferror. 61 MacLisp has a function named error that takes different arguments and can signal either a fatal 62 or a continuable error. 63 |# 64 65 #| 66 Exo 4.2 Vérifier ce que fait la fontion "assoc" dans le poly ou le manuel en ligne. 67 68 15.6. Association Lists 69 70 An association list, or a-list, is a data structure used very frequently in Lisp. 71 An a-list is a list of pairs (conses); each pair is an association. The car of a pair is called 72 the key, and the cdr is called the datum. 73 74 An advantage of the a-list representation is that an a-list can be incrementally augmented 75 simply by adding new entries to the front. Moreover, because the searching function assoc 76 searches the a-list in order, new entries can ``shadow'' old entries. If an a-list is viewed 77 as a mapping from keys to data, then the mapping can be not only augmented but also altered in a 78 non-destructive manner by adding new entries to the front of the a-list. 79 80 Sometimes an a-list represents a bijective mapping, and it is desirable to retrieve a key given a datum. 81 For this purpose, the ``reverse'' searching function rassoc is provided. Other variants of a-list 82 searches can be constructed using the function find or member. 83 84 It is permissible to let nil be an element of an a-list in place of a pair. Such an element is not 85 considered to be a pair but is simply passed over when the a-list is searched by assoc. 86 87 [Function] 88 acons key datum a-list 89 90 acons constructs a new association list by adding the pair (key . datum) to the old a-list. 91 92 (acons x y a) == (cons (cons x y) a) 93 94 This is a trivial convenience function, but I find I use it a lot. 95 96 97 98 [Function] 99 pairlis keys data &optional a-list 100 101 pairlis takes two lists and makes an association list that associates elements of the first list 102 to corresponding elements of the second list. It is an error if the two lists keys and data are not 103 of the same length. If the optional argument a-list is provided, then the new pairs are added to the 104 front of it. 105 106 The new pairs may appear in the resulting a-list in any order; in particular, either forward or 107 backward order is permitted. Therefore the result of the call 108 109 (pairlis '(one two) '(1 2) '((three . 3) (four . 19))) 110 111 might be 112 113 ((one . 1) (two . 2) (three . 3) (four . 19)) 114 115 but could equally well be 116 117 ((two . 2) (one . 1) (three . 3) (four . 19)) 118 119 120 [Function] 121 assoc item a-list &key :test :test-not :key 122 assoc-if predicate a-list 123 assoc-if-not predicate a-list 124 125 [Function] 126 assoc-if predicate a-list &key :key 127 assoc-if-not predicate a-list &key :key 128 129 The omission of :key arguments for these functions in the first edition was probably an oversight. 130 131 Each of these searches the association list a-list. The value is the first pair in the a-list such 132 that the car of the pair satisfies the test, or nil if there is no such pair in the a-list. For example: 133 134 (assoc 'r '((a . b) (c . d) (r . x) (s . y) (r . z))) 135 => (r . x) 136 (assoc 'goo '((foo . bar) (zoo . goo))) => nil 137 (assoc '2 '((1 a b c) (2 b c d) (-7 x y z))) => (2 b c d) 138 139 It is possible to rplacd the result of assoc provided that it is not nil, in order to ``update'' the 140 ``table'' that was assoc's second argument. (However, it is often better to update an a-list by 141 adding new pairs to the front, rather than altering old pairs.) For example: 142 143 (setq values '((x . 100) (y . 200) (z . 50))) 144 (assoc 'y values) => (y . 200) 145 (rplacd (assoc 'y values) 201) 146 (assoc 'y values) => (y . 201) now 147 148 A typical trick is to say (cdr (assoc x y)). Because the cdr of nil is guaranteed to be nil, 149 this yields nil if no pair is found or if a pair is found whose cdr is nil. This is useful 150 if nil serves its usual role as a ``default value.'' 151 152 The two expressions 153 154 (assoc item list :test fn) 155 156 and 157 158 (find item list :test fn :key #'car) 159 160 are equivalent in meaning with one important exception: if nil appears in the a-list in place of 161 a pair, and the item being searched for is nil, find will blithely compute the car of the nil 162 in the a-list, find that it is equal to the item, and return nil, whereas assoc will ignore the 163 nil in the a-list and continue to search for an actual pair (cons) whose car is nil. 164 See find and position. 165 166 Compatibility note: In MacLisp, the assoc function uses an equal comparison rather than eql, 167 which is the default test for assoc in Common Lisp. Where in MacLisp one would write (assoc x y), 168 in Common Lisp one must write (assoc x y :test #'equal) to get the completely identical effect. 169 Similarly, one can get the precise effect, and no more, of the MacLisp (assq x y) by writing in 170 Common Lisp (assoc x y :test #'eq). 171 172 In Interlisp, assoc uses an eq test, and sassoc uses an Interlisp equal test. 173 174 175 [Function] 176 rassoc item a-list &key :test :test-not :key 177 rassoc-if predicate a-list 178 rassoc-if-not predicate a-list 179 180 [Function] 181 rassoc-if predicate a-list &key :key 182 rassoc-if-not predicate a-list &key :key 183 184 The omission of :key arguments for these functions in the first edition was probably an oversight. 185 change_end 186 187 rassoc is the reverse form of assoc; it searches for a pair whose cdr satisfies the test, rather than 188 the car. If the a-list is considered to be a mapping, then rassoc treats the a-list as representing 189 the inverse mapping. For example: 190 191 (rassoc 'a '((a . b) (b . c) (c . a) (z . a))) => (c . a) 192 193 The expressions 194 195 (rassoc item list :test fn) 196 197 and 198 199 (find item list :test fn :key #'cdr) 200 201 are equivalent in meaning, except when the item is nil and nil appears in place of a pair in the a-list. 202 See the discussion of the function assoc. 203 204 |# 205 206 #| 207 Exo 4.3 Définir la fonction "meval-body" qui prend en paramètre une liste d'expressions évaluables 208 et un environnement, qui les évalue en séquence et retourne la valeur retourée par la dernière. 209 |# 210 #| 211 (defun meval-body (liste-expr env) 212 ;; on boul 213 ) 214 |# 215 216 #| 217 Exo 4.4 Définir la fonction "meval-args" qui prend en paramètre une liste d'expressions évaluables 218 et un environnement, qui les évalue en séquence et retourne la liste de leurs valeurs. 219 |# 220 #| 221 (defun meval-args (liste-expr) 222 ) 223 |# 224 225 226 #| 227 Exo 4.5 Définir la fonction "make-env" qui prend en paramètre une liste de symboles, une liste de 228 valeurs et un environnement : construit l'environnement (une liste d'association) en appariant 229 les paramètres aux valeurs correspondantes et signale une exception si paramètres et arguments 230 ne concordent pas. On ne traitera d'abord que le cas des paramètres obligatoires. Si l'environnement 231 passé en paramètre n'est pas vide, le nouvel environnement doit l'inclure. 232 |# 233 #| 234 (defun make-env (liste-symb liste-val env) 235 ) 236 |# 237 238 #| 239 Exo 4.6 Définir la fonction "meval-lambda" qui applique une lambda-fonction quelconque à des valeurs 240 d'arguments dans un certain environnement. Cette fonction servira aussi pour les autres cas 241 d'application de fonction, par exemple pour les macros. 242 Exemple d'utilisation : 243 ((and (consp (car expr)) (eq 'lambda (caar expr))) ; lambda-fonction 244 (meval-lambda (car expr) (meval-args (cdr expr) env) env)) 245 ;; une fonction est un symbole non constant 246 ((get-defun (car expr)) 247 (meval-lambda (get-defun (car expr)) (meval-args (cdr expr) env) ())) 248 ...) 249 |# 250 #| 251 (defun meval-lambda (expr) 252 ) 253 |# 254 255 #| 256 Exo 4.7 Vérifier ce que fait la fonction "get" dans le poly ou le manuel en ligne. 257 258 10.1. The Property List 259 260 Since its inception, Lisp has associated with each symbol a kind of tabular data structure called 261 a property list (plist for short). A property list contains zero or more entries; each entry 262 associates with a key (called the indicator), which is typically a symbol, an arbitrary Lisp object 263 (called the value or, sometimes, the property). There are no duplications among the indicators; a 264 property list may only have one property at a time with a given name. In this way, given a symbol 265 and an indicator (another symbol), an associated value can be retrieved. 266 267 A property list is very similar in purpose to an association list. The difference is that a property 268 list is an object with a unique identity; the operations for adding and removing property-list entries 269 are destructive operations that alter the property list rather than making a new one. Association lists, 270 on the other hand, are normally augmented non-destructively (without side effects) by adding new entries 271 to the front (see acons and pairlis). 272 273 A property list is implemented as a memory cell containing a list with an even number (possibly zero) 274 of elements. (Usually this memory cell is the property-list cell of a symbol, but any memory cell 275 acceptable to setf can be used if getf and remf are used.) Each pair of elements in the list 276 constitutes an entry; the first item is the indicator, and the second is the value. Because property-list 277 functions are given the symbol and not the list itself, modifications to the property list can be 278 recorded by storing back into the property-list cell of the symbol. 279 280 When a symbol is created, its property list is initially empty. Properties are created by using get 281 within a setf form. 282 283 Common Lisp does not use a symbol's property list as extensively as earlier Lisp implementations did. 284 Less-used data, such as compiler, debugging, and documentation information, is kept on property lists 285 in Common Lisp. 286 287 In Common Lisp, the notion of ``disembodied property list'' introduced in MacLisp is eliminated. 288 It tended to be used for rather kludgy things, and in Lisp Machine Lisp is often associated with 289 the use of locatives (to make it ``off by one'' for searching alternating keyword lists). 290 In Common Lisp special setf-like property-list functions are introduced: getf and remf. 291 292 293 [Function] 294 get symbol indicator &optional default 295 296 get searches the property list of symbol for an indicator eq to indicator. The first argument 297 must be a symbol. If one is found, then the corresponding value is returned; otherwise default 298 is returned. 299 300 If default is not specified, then nil is used for default. 301 302 Note that there is no way to distinguish an absent property from one whose value is default. 303 304 (get x y) == (getf (symbol-plist x) y) 305 306 Suppose that the property list of foo is (bar t baz 3 hunoz "Huh?"). Then, for example: 307 308 (get 'foo 'baz) => 3 309 (get 'foo 'hunoz) => "Huh?" 310 (get 'foo 'zoo) => nil 311 312 Compatibility note: In MacLisp, the first argument to get could be a list, in which case the cdr 313 of the list was treated as a so-called ``disembodied property list.'' The first argument to get 314 could also be any other object, in which case get would always return nil. In Common Lisp, it is 315 an error to give anything but a symbol as the first argument to get. 316 317 setf may be used with get to create a new property-value pair, possibly replacing an old pair 318 with the same property name. For example: 319 320 (get 'clyde 'species) => nil 321 (setf (get 'clyde 'species) 'elephant) => elephant 322 and now (get 'clyde 'species) => elephant 323 324 The default argument may be specified to get in this context; it is ignored by setf but may be 325 useful in such macros as push that are related to setf: 326 327 (push item (get sym 'token-stack '(initial-item))) 328 329 means approximately the same as 330 331 (setf (get sym 'token-stack '(initial-item)) 332 (cons item (get sym 'token-stack '(initial-item)))) 333 334 which in turn would be treated as simply 335 336 (setf (get sym 'token-stack) 337 (cons item (get sym 'token-stack '(initial-item)))) 338 339 [Function] 340 remprop symbol indicator 341 342 This removes from symbol the property with an indicator eq to indicator. The property indicator 343 and the corresponding value are removed by destructively splicing the property list. 344 It returns nil if no such property was found, or non-nil if a property was found. 345 346 (remprop x y) == (remf (symbol-plist x) y) 347 348 For example, if the property list of foo is initially 349 350 (color blue height 6.3 near-to bar) 351 352 then the call 353 354 (remprop 'foo 'height) 355 356 returns a non-nil value after altering foo's property list to be 357 358 (color blue near-to bar) 359 360 [Function] 361 symbol-plist symbol 362 363 This returns the list that contains the property pairs of symbol; the contents of the property-list 364 cell are extracted and returned. 365 366 Note that using get on the result of symbol-plist does not work. One must give the symbol itself 367 to get or else use the function getf. 368 369 setf may be used with symbol-plist to destructively replace the entire property list of a symbol. 370 This is a relatively dangerous operation, as it may destroy important information that the 371 implementation may happen to store in property lists. Also, care must be taken that the new property 372 list is in fact a list of even length. 373 374 Compatibility note: In MacLisp, this function is called plist; in Interlisp, it is called getproplist. 375 376 [Function] 377 getf place indicator &optional default 378 379 getf searches the property list stored in place for an indicator eq to indicator. 380 If one is found, then the corresponding value is returned; otherwise default is returned. 381 If default is not specified, then nil is used for default. Note that there is no way to 382 distinguish an absent property from one whose value is default. Often place is computed 383 from a generalized variable acceptable to setf. 384 385 setf may be used with getf, in which case the place must indeed be acceptable as a place to setf. 386 The effect is to add a new property-value pair, or update an existing pair, in the property 387 list kept in the place. The default argument may be specified to getf in this context; 388 it is ignored by setf but may be useful in such macros as push that are related to setf. 389 See the description of get for an example of this. 390 391 Compatibility note: The Interlisp function listget is similar to getf. The Interlisp function 392 listput is similar to using getf with setf. 393 394 [Macro] 395 remf place indicator 396 397 This removes from the property list stored in place the property with an indicator eq to indicator. 398 The property indicator and the corresponding value are removed by destructively splicing the property list. 399 remf returns nil if no such property was found, or some non-nil value if a property was found. 400 The form place may be any generalized variable acceptable to setf. See remprop. 401 402 [Function] 403 get-properties place indicator-list 404 405 get-properties is like getf, except that the second argument is a list of indicators. 406 get-properties searches the property list stored in place for any of the indicators in 407 indicator-list until it finds the first property in the property list whose indicator 408 is one of the elements of indicator-list. Normally place is computed from a generalized 409 variable acceptable to setf. 410 411 get-properties returns three values. If any property was found, then the first two values are 412 the indicator and value for the first property whose indicator was in indicator-list, and 413 the third is that tail of the property list whose car was the indicator (and whose cadr 414 is therefore the value). If no property was found, all three values are nil. Thus the 415 third value serves as a flag indicating success or failure and also allows the search to be 416 restarted, if desired, after the property was found. 417 |# 418 419 #| 420 "Exo 4.8a" Il reste enfin à définir "get-defun". On pourrait construire un environnement spécial - 421 il s'agit bien d'ailleurs d'un environnement spécial, réservé aux fonctions et global - en réutilisant 422 des listes d'association, mais cela poserait divers problèmes techniques et le plus simple est 423 d'utiliser les propriétés des symboles et la fonction "get". On définira alors "get-defun" ainsi : .. 424 |# 425 (defun get-defun (symb) 426 (get symb :defun)) 427 #| 428 ... où "symb" est le symbole, c-à-d le nom de fonction concerné et ":defun" est un 'keyword', 429 c-à-d un symbole constant arbitraire. Cependant, si "get" est bien "setf-able", ce n'est plus 430 le cas de "get-defun". 431 |# 432 #| 433 Exo 4.8 Ecrire "get-defun" sous forme de maro et vérifier que cette nouvelle version est bien 434 setf-able. 435 |# 436 #| 437 (defun get-defun (symb) 438 ) 439 |# 440 441 #| 442 Exo 4.9 Vérifier ce que fait la fonction "symbol-function" dans le poly ou le manuel en ligne. 443 444 [Function] 445 symbol-function symbol 446 447 symbol-function returns the current global function definition named by symbol. 448 An error is signalled if the symbol has no function definition; see fboundp. 449 Note that the definition may be a function or may be an object representing a special 450 form or macro. In the latter case, however, it is an error to attempt to invoke the object 451 as a function. If it is desired to process macros, special forms, and functions equally 452 well, as when writing an interpreter, it is best first to test the symbol with macro-function 453 and special-form-p and then to invoke the functional value only if these two tests both yield false. 454 455 This function is particularly useful for implementing interpreters for languages embedded in Lisp. 456 457 symbol-function cannot access the value of a lexical function name produced by flet or labels; 458 it can access only the global function value. 459 460 The global function definition of a symbol may be altered by using setf with symbol-function. 461 Performing this operation causes the symbol to have only the specified definition as its 462 global function definition; any previous definition, whether as a macro or as a function, 463 is lost. It is an error to attempt to redefine the name of a special form (see table 5-1). 464 465 change_begin 466 X3J13 voted in June 1988 (FUNCTION-TYPE) to clarify the behavior of symbol-function in the 467 light of the redefinition of the type function. 468 469 * It is permissible to call symbol-function on any symbol for which fboundp returns true. 470 Note that fboundp must return true for a symbol naming a macro or a special form. 471 472 * If fboundp returns true for a symbol but the symbol denotes a macro or special form, 473 then the value returned by symbol-function is not well-defined but symbol-function will 474 not signal an error. 475 476 * When symbol-function is used with setf the new value must be of type function. 477 It is an error to set the symbol-function of a symbol to a symbol, a list, or the 478 value returned by symbol-function on the name of a macro or a special form. 479 |# 480 481 #| 482 Exo 4.10 Vérifier ce que fait la fonction "special-form-p" dans le poly ou le manuel en ligne. 483 484 [Function] 485 special-form-p symbol 486 487 The function special-form-p takes a symbol. If the symbol globally names a special form, then 488 a non-nil value is returned; otherwise nil is returned. A returned non-nil value is typically 489 a function of implementation-dependent nature that can be used to interpret (evaluate) the special form. 490 491 It is possible for both special-form-p and macro-function to be true of a symbol. This is 492 possible because an implementation is permitted to implement any macro also as a special form 493 for speed. On the other hand, the macro definition must be available for use by programs 494 that understand only the standard special forms listed in table 5-1. 495 |# 496 497 #| 498 Exo 4.11 Vérifier ce que fait la fonction "fboundp" dans le poly ou le manuel en ligne. 499 500 [Function] 501 fboundp symbol 502 503 fboundp is true if the symbol has a global function definition. Note that fboundp is true 504 when the symbol names a special form or macro. macro-function and special-form-p may be used 505 to test for these cases. 506 507 change_begin 508 X3J13 voted in June 1988 (FUNCTION-TYPE) to emphasize that, despite the tightening of the 509 definition of the type function, fboundp must return true when the argument names a special 510 form or macro. 511 512 See also symbol-function and fmakunbound. 513 514 X3J13 voted in March 1989 (FUNCTION-NAME) to extend fboundp to accept any function-name (a 515 symbol or a list whose car is setf-see section 7.1). Thus one may write (fboundp '(setf cadr)) 516 to determine whether a setf expansion function has been globally defined for cadr. 517 change_end 518 |# 519 520 #| 521 Exo 4.12 Tester "symbol-function", "special-form-p" et "fboundp" sur des arguments de différents types : 522 autre que symbol, sur des symboles avec ou sans définition fonctionnelle, et enfin avec des définitions 523 fonctionnelles de différents types (formes syntaxiques, macros, fonctions globales ou locales). 524 |# 525 526 #| 527 Exo 4.13 Méta-définir les fonctions "fact" et "fibo". Les tester. 528 |# 529 #| 530 (defun fact-meta () 531 ) 532 |# 533 #| 534 (defun fibo-meta () 535 ) 536 |# 537 538 #| 539 Exo 4.14 Considérer l'expression (meval '(meval '(fibo 10))) et en déduire quelle va 540 être la première erreur produite par son évaluation. Vérifier par un test. Si ça marche du 541 premier coup, c'est mauvais signe : vérifier que meval a bien été méta-définie (par 542 (meval '(defun meval ...))) ! 543 |# 544 545 #| 546 Exo 4.15 Etendre la définition de "make-env" aux mots-clés &optional et &rest. 547 On se basera sur le fait que la spécification des ces mots-clés repose sur un automate 548 implicite. Expliciter l'automate et l'implémentation par des fonctions adéquates 549 (voir aussi Chapitre 3, en particulier la section 3.3) 550 |# 551 552 (defun meval (expr &optional env) 553 (cond 554 ((and (atom expr) (constantp expr)) ; constante atomique 555 (print "constante atomique") 556 expr) 557 ((atom expr) ; atom non constant, donc variable 558 (print "atom non constant, donc variable") 559 (let ((cell (assoc expr env))) 560 (if cell 561 (cdr cell) 562 (error "~s n'est pas une variable" expr)))) 563 ;; plus d'atome à partir d'ici 564 ((and (consp (car expr)) (eq 'lambda (caar expr))) ;; lambda-fonction 565 (print "lambda-fonction") 566 ;; ((meval-lambda (car expr) (meval-args (cdr expr) env) env)) 567 (meval-body (cddar expr) 568 (make-env (cadar expr) 569 (meval-args (cdr expr) env) 570 env))) 571 ((or (not (symbolp (car expr))) (constantp (car expr))) ;; ?? en cas de "nil" 572 ;; une fonction est un symbole non constant 573 (error "~s ne peut être une fonction" (car expr))) 574 ; ((get-defun (car expr)) 575 ; (let ((fun (get-defun (car expr)))) 576 ; ;; (meval-lambda (get-defun (car expr)) (meval-args (cdr expr) env) ())) 577 ; (meval-body (cddr fun) 578 ; (make-env (cadr fun) 579 ; (meval-args (cdr expr) env) 580 ; ())))) 581 ; ((eq 'defun (car expr)) 582 ; (setf (get-defun (cadr expr)) 583 ; '(lambd ,@(cddr expr)))) 584 ((eq 'quote (car expr)) ;; quote 585 (print "quote") 586 (cadr expr)) 587 ((not (fboundp (car expr))) ;; faux gd // à étudier 588 (error "~s symbole sans définition fonctionnelle" (car expr))) 589 ((special-form-p (car expr)) 590 (print "forme spéciale non implémentée") 591 (if (null env) 592 (eval expr) 593 (error "~s forme spéciale NYI" (car expr)))) 594 ; (t (apply (symbol-function (car expr)) (meval-args (cdr expr) env))) 595 ; TODO : la fin est fausse 596 ((null env) 597 (eval expr)) 598 (t (error "impossible d'évaluer ~s dans l'environnement ~s" expr env)) 599 ;(t (eval expr)) ; triche 600 601 )) 602 603 #| 604 Exo 4.16 Définir cette fonction mload : (voir fascicule, page 23) on regardera dans le manuel le 605 chapitre sur les entrées-sorties, en particulier les fonctions open, read et close, ainsi que le traitement 606 de la fin de fichier 607 |# 608 609 #| 610 23.2. Opening and Closing Files 611 When a file is opened, a stream object is constructed to serve as the file system's ambassador 612 to the Lisp environment; operations on the stream are reflected by operations on the file in the 613 file system. The act of closing the file (actually, the stream) ends the association; the 614 transaction with the file system is terminated, and input/output may no longer be performed 615 on the stream. The stream function close may be used to close a file; the functions described 616 below may be used to open them. The basic operation is open, but with-open-file is usually 617 more convenient for most applications. 618 619 [Function] 620 open filename &key :direction :element-type :if-exists :if-does-not-exist :external-format 621 622 This returns a stream that is connected to the file specified by filename. The filename is the 623 name of the file to be opened; it may be a string, a pathname, or a stream. (If the filename 624 is a stream, then it is not closed first or otherwise affected; it is used merely to provide 625 a file name for the opening of a new stream.) 626 627 The keyword arguments specify what kind of stream to produce and how to handle errors: 628 629 :direction 630 This argument specifies whether the stream should handle input, output, or both. 631 :input 632 The result will be an input stream. This is the default. 633 :output 634 The result will be an output stream. 635 :io 636 The result will be a bidirectional stream. 637 :probe 638 The result will be a no-directional stream (in effect, the stream is created and then closed). This is useful for determining whether a file exists without actually setting up a complete stream. 639 :element-type 640 This argument specifies the type of the unit of transaction for the stream. Anything that can 641 be recognized as being a finite subtype of character or integer is acceptable. In particular, 642 the following types are recognized: 643 string-char 644 The unit of transaction is a string-character. The functions read-char and/or write-char 645 may be used on the stream. This is the default. 646 character 647 The unit of transaction is any character, not just a string-character. The functions read-char and/or write-char may be used on the stream. 648 649 to eliminate the type string-char, add the type base-character, and redefine open to use the type character as the default :element-type. 650 651 The preceding two possibilities should therefore be replaced by the following. 652 character 653 The unit of transaction is any character, not just a string-character. The functions 654 read-char and write-char (depending on the value of the :direction argument) may be 655 used on the stream. This is the default. 656 base-character 657 The unit of transaction is a base character. The functions read-char and write-char 658 (depending on the value of the :direction argument) may be used on the stream. 659 (unsigned-byte n) 660 The unit of transaction is an unsigned byte (a non-negative integer) of size n. 661 The functions read-byte and/or write-byte may be used on the stream. 662 unsigned-byte 663 The unit of transaction is an unsigned byte (a non-negative integer); the size of the byte 664 is determined by the file system. The functions read-byte and/or write-byte may be used 665 on the stream. 666 (signed-byte n) 667 The unit of transaction is a signed byte of size n. 668 The functions read-byte and/or write-byte may be used on the stream. 669 signed-byte 670 The unit of transaction is a signed byte; the size of the byte is determined by the 671 file system. The functions read-byte and/or write-byte may be used on the stream. 672 bit 673 The unit of transaction is a bit (values 0 and 1). The functions read-byte and/or 674 write-byte may be used on the stream. 675 (mod n) 676 The unit of transaction is a non-negative integer less than n. The functions read-byte 677 and/or write-byte may be used on the stream. 678 :default 679 The unit of transaction is to be determined by the file system, based on the file it finds. The type can be determined by using the function stream-element-type. 680 :if-exists 681 This argument specifies the action to be taken if the :direction is :output or :io and a file of 682 the specified name already exists. If the direction is :input or :probe, this argument is ignored. 683 :error 684 Signals an error. This is the default when the version component of the 685 filename is not :newest. 686 :new-version 687 Creates a new file with the same file name but with a larger version number. This is the 688 default when the version component of the filename is :newest. 689 :rename 690 Renames the existing file to some other name and then creates a new file with the 691 specified name. 692 :rename-and-delete 693 Renames the existing file to some other name and then deletes it (but does not expunge it, 694 on those systems that distinguish deletion from expunging). Then create a new file with the specified name. 695 :overwrite 696 Uses the existing file. Output operations on the stream will destructively modify the 697 file. If the :direction is :io, the file is opened in a bidirectional mode that allows 698 both reading and writing. The file pointer is initially positioned at the beginning of 699 the file; however, the file is not truncated back to length zero when it is opened. 700 This mode is most useful when the file-position function can be used on the stream. 701 :append 702 Uses the existing file. Output operations on the stream will destructively modify the 703 file. The file pointer is initially positioned at the end of the file. If the :direction 704 is :io, the file is opened in a bidirectional mode that allows both reading and writing. 705 :supersede 706 Supersedes the existing file. If possible, the implementation should arrange not to 707 destroy the old file until the new stream is closed, against the possibility that the 708 stream will be closed in ``abort'' mode (see close). This differs from :new-version in 709 that :supersede creates a new file with the same name as the old one, rather than a 710 file name with a higher version number. 711 nil 712 Does not create a file or even a stream, but instead simply returns nil to indicate failure. 713 If the :direction is :output or :io and the value of :if-exists is :new-version, then the version 714 of the (newly created) file that is opened will be a version greater than that of any other file 715 in the file system whose other pathname components are the same as those of filename. 716 If the :direction is :input or :probe or the value of :if-exists is not :new-version, and 717 the version component of the filename is :newest, then the file opened is that file already 718 existing in the file system that has a version greater than that of any other file in the file 719 system whose other pathname components are the same as those of filename. 720 :if-does-not-exist 721 This argument specifies the action to be taken if a file of the specified name does not already exist. 722 :error 723 Signals an error. This is the default if the :direction is :input, or if the :if-exists 724 argument is :overwrite or :append. 725 :create 726 Creates an empty file with the specified name and then proceeds as if it had 727 already existed (but do not perform any processing directed by the :if-exists argument). 728 This is the default if the :direction is :output or :io, and the :if-exists argument is 729 anything but :overwrite or :append. 730 nil 731 Does not create a file or even a stream, but instead simply returns nil to indicate failure. 732 This is the default if the :direction is :probe. 733 :external-format 734 This argument specifies an implementation-recognized scheme for representing characters in files. 735 The default value is :default and is implementation-defined but must support the base characters. 736 An error is signaled if the implementation does recognize the specified format. 737 738 This argument may be specified if the :direction argument is :input, :output, or :io. 739 It is an error to write a character to the resulting stream that cannot be represented 740 by the specified file format. (However, the #\Newline character cannot produce such an 741 error; implementations must provide appropriate line division behavior for all character streams.) 742 743 When the caller is finished with the stream, it should close the file by using the close function. The with-open-file form does this automatically, and so is preferred for most purposes. open should be used only when the control structure of the program necessitates opening and closing of a file in some way more complex than provided by with-open-file. It is suggested that any program that uses open directly should use the special form unwind-protect to close the file if an abnormal exit occurs. 744 745 [Macro] 746 with-open-file (stream filename {options}*) 747 {declaration}* {form}* 748 with-open-file evaluates the forms of the body (an implicit progn) with the variable stream bound 749 to a stream that reads or writes the file named by the value of filename. The options are evaluated 750 and are used as keyword arguments to the function open. 751 752 When control leaves the body, either normally or abnormally (such as by use of throw), the file 753 is automatically closed. If a new output file is being written, and control leaves abnormally, 754 the file is aborted and the file system is left, so far as possible, as if the file had never 755 been opened. Because with-open-file always closes the file, even when an error exit is taken, 756 it is preferred over open for most applications. 757 758 filename is the name of the file to be opened; it may be a string, a pathname, or a stream. 759 760 For example: 761 (with-open-file (ifile name 762 :direction :input) 763 (with-open-file (ofile (merge-pathname-defaults ifile 764 nil 765 "out") 766 :direction :output 767 :if-exists :supersede) 768 (transduce-file ifile ofile))) 769 ... 770 (with-open-file (ifile name 771 :direction :input 772 :if-does-not-exist nil) 773 ;; Process the file only if it actually exists. 774 (when (streamp name) 775 (compile-cobol-program ifile))) 776 777 Implementation note: While with-open-file tries to automatically close the stream on exit from 778 the construct, for robustness it is helpful if the garbage collector can detect discarded 779 streams and automatically close them. 780 781 ... 782 783 READ 784 785 [Function] 786 read &optional input-stream eof-error-p eof-value recursive-p 787 788 read reads in the printed representation of a Lisp object from input-stream, builds a corresponding 789 Lisp object, and returns the object. 790 791 Note that when the variable *read-suppress* is not nil, then read reads in a printed representation 792 as best it can, but most of the work of interpreting the representation is avoided (the intent 793 being that the result is to be discarded anyway). For example, all extended tokens produce 794 the result nil regardless of their syntax. 795 796 |# 797 (defun mload () 798 ) 799 800 #| 801 Exo 4.17 - Définir 'get-defmacro' comme une macro. 802 |# 803 804 #| 805 Exo 4.18 - Définir la fonction 'displace' qui prend en argument 2 cellules, met dans la première 806 le contenu de la seconde et retourne la première. Rajouter le cas où le résultat de la macro-expansion 807 est un atome. 808 |# 809 810 #| 811 Exo 4.19 - Définir la fonction 'm-macroexmand-1' qui expanse une fois une macro méta-définie 812 par analogie avec 'macroexpand-1' 813 |# 814 815 #| 816 Exo 4.20 - Définir la fonction m-macroexpand qui expanse complètement une macro métadéfinie, 817 par analogie avec 'macroexpand'. Le principe de 'macroexpand' est d'appliquer 'macroexpand-1' 818 tant que le résultat de l'expansion est toujours une macro. On traitera dans cette fonction 819 aussi bien les macros méta-définies que les prédéfinies. 820 |# 821 822 #| 823 Exo 4.21 - Définir la fonction 'meval-let' qui méta-évalue une expression 'let'. 824 |# 825 826 #| 827 Exo 4.22 - Définir la fonction 'meval-cond' qui méta-évalue une expression 'cond', 828 comme si c'était une forme syntaxique. 829 |# 830 831 #| 832 Exo 4.23 - Etendre 'msetf' à l'affectation d'arité quelconque. 833 |# 834 835 #| 836 Exo 4.24 - Intégrer la macro-expansion de 'place' dans 'msetf' : traiter les deux cas de macros 837 méta-définies et prédéfinies. 838 |# 839 840 #| 841 Exo 4.25 - Au lieu d'énumérer dans 'msetf' toutes les fonctions setf-able, le mieux est 842 d'évaluer tous les arguments de 'place', de reconstruire l'expression 'place' en remplaçant les arguments 843 par leur quotée, d'évaluer 'val', puis de reconstruire l'expression 'expr' avec 'place' transformée et 844 la valeur de 'val' quotée. On peut alors évaluer 'expr' pour effectuer l'affectation : tous les 845 arguments étant quotés, cette évaluation peut se faire dans un environnement vide. 846 |# 847 848 #| 849 Exo 4.26 - Définir 3 fonctions de l'exemple du compteur dans le polycopié LISP 850 |# 851 852 #| 853 Exo 4.27 - Définir cette fonction 'meval-args*' qui est à 'meval-args' ce que 854 'list*' est à 'list'. 855 |# 856 857 #| 858 Exo 4.28 - Tester les fermetures sur le schéma de terminalisation des récursions enveloppées 859 par passage de continuation. Voir polycopié de LISP. 860 |# 861 862 #| 863 Exo 4.29 - Redéfinir les fonctions 'make-closure' et 'meval-closure' pour tenir compte de 864 l'environnement fonctionnel. 865 |# 866 867 #| 868 Exo 4.30 - Etendre le traitement de 'function' aux fonctions locales. 869 |# 870 871 #| 872 Exo 4.31 - Définir la fonction 'make-flet-fenv' qui construit cet environnement fonctionnel. 873 |# 874 875 #| 876 Exo 4.32 - Définir la fonction 'make-labels-fenv' qui construit cet environnement fonctionnel 877 circulaire. On appellera 'make-flet-fenv' en lui passant un environnement fonctionnel "vide" 878 qu'il s'agira ensuite de remplacer par son résultat même, par exemple par appel de 'displace'. 879 |# 880 881 #| 882 Exo 4.33 - Définir la fonction 'destruct' qui construit un environnement de façon similaire à 883 'make-env' mais avec la destructuration. 884 |# 885 886 #| 887 Exo 4.34 - Traiter la forme syntaxique destructuring-bind' dans 'meval'. 888 |# 889 890 #| 891 Exo 4.35 - Etendre la fonction 'make-env' pour qu'elle inclue la destructuration sur les 892 paramètres obligatoires, tout en conservant la possibilité des mots-clés &optional, &key, 893 &rest avec leur syntaxe habituelle. 894 |# 895 896 #| 897 Exo 4.36 - Etendre la fonction 'destruct' pour qu'elle interdise la double occurrence d'un 898 paramètre dans l'arbre. 899 |# 900 901 #| 902 Exo 4.37 - Définir la fonction 'match' qui apparie un motif et une valeur dans un 903 environnement qu'elle étend et retourne. En cas d'échec, retourne le mot-clé :fail. 904 La fonction est similaire à 'destruct' mais elle intègre ces nouvelles contraintes. 905 |# 906 907 #| 908 Exo 4.38 - Définir la fonction 'meval-case-match' qui implémente la forme syntaxique 909 'case-match' dans le méta-évaluateur. 910 |# 911 912 #| 913 Exo 4.39 - Définir la macro 'defil' qui construit progressivement la 'case-match' qui 914 fait office de corps de la fonction. 915 Le filtrage s'applique particulièrement bien aux macros, les différents motifs correspondant 916 à l'analyse par cas à faire sur la syntaxe de l'expression. 917 |# 918 919 #| 920 Exo 4.40 - Définir la macro 'defil-macro' qui construit progressivement le 'case-match' 921 qui fait office de corps d'une macro. 922 |# 923 924 #| 925 Exo 4.41 - Définir la macro 'or' par filtrage. Faire de même pour les différents exemples de 926 macros du polycopié de LISP. 927 |# 928 929 #| 930 Exo 4.42 - Définir la fonction 'rewrite-1' qui prend en entrée une donnée et une liste 931 de règles de réécriture et réécrit la donnée suivant la règle de réécriture donnée par le 932 motif et la production. Retourne :fail si l'appariement ne réussit pas. 933 |# 934 935 #| 936 Exo 4.43 - Définir la fonction 'rewrite' qui prend en entrée une donnée et une liste de règles 937 de réécriture et réécrit la donnée tant qu'une règle s'applique. 938 |# 939 940 #| 941 Exo 4.44 - Définir la macro 'defrewrite-macro' qui définit une macro par des règles de 942 réécriture, comme les 'let-syntax' et 'syntax-rules' de SCHEME. Cela revient à remplacer 943 la construction explicite de l'expansion, avec 'backquote' par une construction implicite où 944 l'action associée à chaque motif est implicitement 'backquotée' et où chaque variable 945 figurant dans le motif y est implicitement virgulée. 946 |# 947 948 #| 949 Exo 4.45 - Définir la macro 'or' par règles de réécriture et faire de même pour les différents 950 exemples de macros du polycopié de LISP. Comment pourrait-ont éviter avec 'or' les problèmes 951 de capture de variable ? (cf. Section sur les macros dans le chapitre 3 du polycopié LISP). 952 |# 953 954 #| 955 Exo 4.46 - Etendre la fonction 'match' aux variables segments. On définira deux fonctions 956 auxiliaires pour tester si une variable est segment et pour en extraire la variable simple 957 correspondante. Pour simplifier ce traitement, on peut utiliser une forme parenthésée pour 958 les segments, par exemple (*x), avec le risque de limiter les squelettes possibles : il faut 959 en tout cas bien placer la clause sur les segments. 960 |# 961 962 #| 963 Exo 4.47 - Définir dans 'meval' les deux formes syntaxiques 'delay' et 'force'. 964 |# 965 966 #| 967 Exo 4.48 - Il n'est en fait pas nécessaire de passer par des formes syntaxiques pour définir 968 les retardements. Définir 'delay' comme une macro et 'force' comme une fonction. 969 |# 970 971 #| 972 Exo 4.49 - Définir le flot 'enum-fibo' qui énumère la suite de Fibonacci. Voir aussi la 973 fonction 'next-fibo' dans le polycopié de LISP. 974 |# 975 976 #| 977 Exo 4.50 - Définir le flot enum-prime qui énumère les nombres premiers. Voir aussi la 978 fonction 'next-prime' dans le polycopié de LISP. 979 |# 980 981 #| 982 Exo 4.51 - Définir la fonction 'scheme-symbol-function'. 983 |# 984 985 #| 986 (deftest jc-meval 987 (meval "bonjour") 988 "bonjour") 989 |#