mardi 3 mars 2015

17-LES TYPES * Retour sur LES FERMETURES et LES BLOCKS * LES DOCUMENTATIONS.

>>>>
LES TYPES:

(defun foo (x)
  (declare (type float x))
  (format t "Voici un nombre flottant: ~a." x)
  'fin)
FOO définit une fonction contenant une déclaration de type
l'argument de foo doit être un nombre flottant

(foo pi)
Voici un nombre flottant: 3.141592653589793d0.
FIN pi est bien un nombre flottant

(foo 3/2)
; Evaluation aborted on #. 3/2 est un rationnel, donc erreur

(type-of s)
ESSAI S est du type ESSAI (ESSAI étant précédemment définit comme une structure)

(type-of 3)
(INTEGER 0 536870911) 3 est un entier

(type-of #C(3 2))
(COMPLEX (INTEGER 2 3)) #C(3 2) est un nombre complexe et les parties réelles et imaginaires sont des entiers.

(type-of #C(3 2.0))
(COMPLEX (SINGLE-FLOAT 2.0 3.0)) #C(3 2.0) est un nombre complexe et les parties réelles (après conversion) et imaginaires sont des flottants simples.

(type-of 2/3)
RATIO 2/3 est un rationnel non entier
RATIO est un type propre au langage LISP qui permet de donner un résultat                                         sous sa forme exacte

Donc TYPE-OF rend le type de l'objet passé en argument.

TYPEP:

(typep *x* 'array)
T rend vrai car *x* a été défini comme un tableau précédemment
noter le quote ' devant array, sinon array est pris comme une variable, d'où: erreur
rend NIL si *x* n'est pas un tableau

Suivant le cas, pour contrôler le type on utilise les mots (quotés) suivants:
array   float           package          sequence           bit-vector                 function
pathname short-float   character   hash-table         random-state            single-float
complex        integer        ratio stream               condition   long-float
rational        string          cons                 null                    readtable symbol     double-float
number       restart        vector               fixnum              t

LES FERMETURES:

Quelques exemples:

(let ((a 0))
  (defun compte ()
    (format t "a = ~a~%" (incf a)))
  (defun réinitialisation (&optional (néo-a 0))
    (setf a néo-a)
    (format t "a = ~a~%" a)))
RÉINITIALISATION a est une variable locale et les fonctions compte et réinitialisation sont des fermetures car définies dans un LET. la variable locale est évidemment inaccessible.

(compte)
a = 1
NIL au 1er appel à compte, A est incrémenté et le résultat affiché

(compte)
a = 2
NIL idem

(réinitialisation -1)
a = -1
NIL à l'appel de la fonction réinitialisation, la valeur optionnelle de a est -1 (0 par défaut),
valeur ensuite affichée

(compte)
a = 0
NIL à l'appel de compte, a est incrémenté avant d'être affiché

__________________________________________________________________________

Exemple d'utilisation de fermetures pour montrer le fonctionnement de BLOCK et RETURN-FROM:

(defparameter a 0)              a doit être définie lors de l'appel à la fonction anonyme invoquée par
       FUNCALL dans ce qui suit:

(let ((a 0))
  (format t "Entrée dans LET~%")
  (defun compte () ;1ère fermeture (utilisée pour incrémenter a)
    (format t "a = ~a~%" (incf a)))
  (defun réinitialisation (&optional (néo-a 0)) ;2ème fermeture (pour réinitialiser a)
    (setf a néo-a)
    (format t "a = ~a~%" a))
  (defun foo () ;3ème fermeture pour voir les blocs
    (if (> a 4) (réinitialisation)) ;a repasse à 0 si a>4
    (format t " Entrée dans FOO~%")
    (block k ;un bloc k dans la fonction foo
      (format t "  Entrée dans le bloc k~%")
      (bar #'(lambda () (if (= a 3) (progn (format t "  Sortie conditionnelle du bloc k~%") (return-from k)))))
      (format t "  Sortie du bloc k~%"))
    (format t " Sortie de FOO~%")
    (compte))
  (format t "Sortie du LET~%"))

(defun bar (fn) ;cette fonction est appelée dans la fermeture foo
  (format t "   Entrée dans BAR~%")
  (block l ;un bloc l dans la fonction bar
    (format t "    Entrée dans le bloc l~%")
    (baz #'(lambda () (if (= a 2)
  (progn (format t "    Sortie conditionnelle du bloc l~%") (return-from l))
  (funcall fn))))   ;invocation de lambda (fn) par FUNCALL, si a différent de 2
    (format t "    Sortie du bloc l~%"))
  (format t "   Sortie de BAR~%"))

(defun baz (fn) ;cette fonction est appelée dans la fonction bar
  (format t "     Entrée dans BAZ~%")
  (block m ;un bloc m dans la fonction baz
    (format t "      Entrée dans le bloc m~%")
    (funcall fn) ;invocation inconditionnelle de lambda (fn) par FUNCALL
    (format t "      Sortie du bloc m~%"))
  (format t "     Sortie de BAZ~%"))

Pour a = 3, on obtient à l'appel de foo (en utilisant réinitialisation et compte préalablement):

(foo)
 Entrée dans FOO
  Entrée dans le bloc k
   Entrée dans BAR
    Entrée dans le bloc l
     Entrée dans BAZ
      Entrée dans le bloc m
  Sortie conditionnelle du bloc k on voit, ici, que BAR, bloc l, BAZ et bloc m sortent, également,                                                               de la pile
 Sortie de FOO
NIL
________________________________________________________________________________________________________________________
DOCUMENTATION: sur les fonctions et les variables.

(defun la-fonction (x)
  "rend le carré du nombre passé en argument" ;documentation sur la fonction
  (if (numberp x)
      (print (* x x))
      "L'argument doit être un nombre"))
LA-FONCTION

(defvar *la-variable* 15 "Une variable globale")
*LA-VARIABLE*                   définition d'une variable globale avec documentation

(apropos 'la-)
*LA-VARIABLE* (bound)
LA-
LA-FONCTION (fbound)
SB-IMPL::VANILLA-OPEN-ERROR
; No value donne des indications sur les variables et fonctions commençants par la-

(documentation 'la-fonction 'function)
"rend le carré du nombre passé en argument" rend la documentation de la-fonction

(documentation '*la-variable* 'variable)
"Une variable globale" rend la documentation de *la-variable*

Le 2ème argument (quoté) passé à DOCUMENTATION peut être function, variable, structure, type, setf et T.

Pour connaître la documentation de plusieurs fonctions contenue dans une liste:

(dolist (x '(cons car cdr)) (print x) (print (documentation x 'function)))
CONS
"Return a list with SE1 as the CAR and SE2 as the CDR."
CAR
"Return the 1st object in a list."
CDR
"Return all but the first object in a list."
NIL

DESCRIBE:

(describe 'la-fonction)
COMMON-LISP-USER::LA-FONCTION
  [symbol]

LA-FONCTION names a compiled function:
  Lambda-list: (X)
  Derived type: (FUNCTION (T)
                 (VALUES (OR NUMBER (SIMPLE-ARRAY CHARACTER (30)))
                         &OPTIONAL))
  Documentation:
    rend le carré du nombre passé en argument
  Source form:
    (SB-INT:NAMED-LAMBDA LA-FONCTION
        (X)
      (BLOCK LA-FONCTION
        (IF (NUMBERP X)
            (PRINT (* X X))
            "L'argument doit être un nombre")))
rend une description de la fonction et de toutes les informations associées


INSPECT: pour inspecter les propriétés d'un objet.

(inspect 'car)

The object is a SYMBOL.
0. Name: "CAR"
1. Package: #
2. Value: "unbound"
3. Function: #
4. Plist: NIL
> 0                             ici, on demande des renseignements sur le nom

The object is a VECTOR of length 3.
0. #\C
1. #\A
2. #\R
> 1

The object is an ATOM:
  #\A
> q                            on quitte INSPECT

; No value

Voici quelques raccourcis utiles, sous SLIME, liés à la documentation sur un symbole:

Placer le curseur sur le symbole d'abord, puis:
C-c C-d d donne la même chose que DESCRIBE et l'affiche dans un tampon (EMACS).
C-c C-D f décrit la fonction dans un tampon.
C-c C-d h ouvre l'hyperspec dans un navigateur à la page correspondant au symbole.
C-c C-d a recherche un apropos concernant le terme demandé dans le mini-buffer.

C-c I lance SLIME inspector. Entrer l'expression à inspecter (ex: (fac 5)), et valider.
    se déplacer sur l'objet à détailler et valider. l pour revenir en arrière.
q pour quitter l'inspecteur.

Prochainement:  LES SYMBOLES.

Aucun commentaire:

Enregistrer un commentaire