www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

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 |#