samedi 13 décembre 2014

10-Compléments sur quelques fonctions.

>>>>
Liste des symboles rencontrés dans ce chapitre:
CONS CAR CDR FIRST REST LIST NCONC APPEND SUBSTITUTE NSUBSTITUTE REVERSE NREVERSE TAILP LIST* CONSP ATOM LISTP NULL MAPCAR MAPLIST MAPCAN MAPCON MAPC MAPL 

Compléments sur quelques fonctions.

CONS:
CAR:
CDR:
FIRST:
REST:

(cons 1 2)
(1 . 2)

(car (cons 1 2))
1

(first (cons 1 2))
1 FIRST est synonyme de CAR (moins dénué de sens)

(cdr (cons 1 2))
2

(rest (cons 1 2))
2 REST est synonyme de CDR (moins dénué de sens)

CAR, CDR, FIRST, REST sont SETF-ables (pas LAST):

(defparameter *cons* (cons 1 2))
*CONS*

*cons*
(1 . 2)

(setf (car *cons*) 10)
10

*cons*
(10 . 2)

(setf (first *cons*) 15)
15

*cons*
(15 . 2)

(setf (cdr *cons*) 20)
20

*cons*
(15 . 20)

(setf (rest *cons*) 25)
25

*cons*
(15 . 25)

Lisp réduit automatiquement les valeurs pointées quand cela correspond à des listes.

'(1 . nil)
(1)

'(1 . (2))
(1 2)

(cons 1 nil)
(1)

(cons 1 (cons 2 nil))
(1 2)

(cons 1 (cons 2 (cons 3 nil)))
(1 2 3)

Ces 3 lignes précédentes s'écrivent plus simplement avec la fonction LIST:

(list 1)
(1)

(list 1 2)
(1 2)

(list 1 2 3)
(1 2 3)

Et aussi:

(cons 'a (cons 'b nil))
(A B)

(list 'a 'b)
(A B)

Les cellules cons peuvent contenir tout type de valeurs, donc les listes aussi.

NCONC:
APPEND:

(defparameter *x* (list 1 2 3))
*X*

(nconc *x* (list 4 5 6))
(1 2 3 4 5 6)

*x*
(1 2 3 4 5 6) *x* change

Alors que:

(append *x* (list 7 8 9))
(1 2 3 4 5 6 7 8 9)

*x*
(1 2 3 4 5 6) *x* ne change pas

SUBSTITUTE:
NSUBSTITUTE:

(substitute 10 1 *x*)
(10 2 3 4 5 6)

*x*
(1 2 3 4 5 6) *x* ne change pas

(nsubstitute 20 2 *x*)
(1 20 3 4 5 6)

*x*
(1 20 3 4 5 6) *x* change

REVERSE:
NREVERSE:

(reverse *x*)
(6 5 4 3 20 1)

*x*
(1 20 3 4 5 6) *x* ne change pas

(nreverse *x*)
(6 5 4 3 20 1)

*x*
(1) *x* change avec destruction


TAILP:

(tailp 2 '(3 4 1 . 2))
T     rend T si l'objet passé en 1er argument se trouve dans la dernière
  cellule de la liste passée en 2ème argument

(tailp nil (list 1 2))
T la dernière cellule d'une liste contient souvent NIL

(list* 1 2 3 4)
(1 2 3 . 4)     place le dernier argument dans la dernière cellule

(tailp 4 (list* 1 2 3 4))
T           4 est bien dans la dernière cellule

(tailp 4 '(1 2 3 4))
NIL              le dernier élément n'est pas dans la dernière cellule

CONSP:

(consp '(a b c))
T              teste si l'argument est un doublet (une liste non vide)

(consp ())
NIL              NIL n'est pas un doublet

(consp '(a . b))
T

ATOM: opérateur primitif n°2, c'est un prédicat qui rend T ou NIL
tout ce qui n'est pas un doublet est un atome et réciproquement.

(atom 1)
T            teste si l'argument est un atome (le chiffre 1 est un atome)
             c'est à dire n'est pas un doublet

(atom 'a)
T     la lettre a (quotée!) est un atome

(atom #(1 2 3))
T           un vecteur est un atome

(atom '(1 2 3))
NIL           une liste n'est pas un atome

(atom nil)
T           NIL n'est pas un doublet

On en déduit que (atom x) est équivalent à (not (consp x))

LISTP:

(listp '(a b c))
T          teste si l'argument est un doublet ou est NIL

(listp ())
T          NIL n'est pas un doublet, mais est bien une liste

(listp '(a . b))
T          Un doublet est une liste

NIL est donc un atome et une liste à la fois.

NULL:

(null '(a b c))
NIL          teste si l'argument est NIL

(null ())
T         (prédicat de vacuité)

(null '(nil))
NIL         la liste (nil) n'est pas vide


LES MAPs:

MAPCAR:

MAPCAR n'a pas besoin du type rendu comme avec MAP.
Il lui faut la fonction (1er argument), la ou les listes (les autres arguments) dont les éléments
sont les arguments de la fonction. MAPCAR rend une liste de résultats de la fonction.
MAPCAR s'applique au CAR des CDR successifs d'une liste propre (liste initiale comprise).
Il en est de même de MAPC et MAPCAN.
MAPC, MAPCAR et MAPCAN sont dits de la même famille.
MAPL, MAPLIST et MAPCON forme une autre famille: elles s'appliquent aux listes initiales, puis aux CDR successifs de ces listes.

(mapcar #'(lambda (x) (* 2 x)) (list 1 2 3))
(2 4 6)     rend le double de chaque élément de la liste

(mapcar #'+ (list 1 2 3) (list 10 20 30))
(11 22 33)  rend la somme des éléments des deux listes.

Si les listes n'ont pas le même nombre d'éléments, c'est une liste de
moindre éléments qui est rendue:

(mapcar #'+ (list 1 2 3) (list 10 20))
(11 22)     2 éléments rendus au lieu de 3

(mapcar #'car '((1 a) (2 b) (3 c)))
(1 2 3)     rend le premier élément de chaque liste de la liste

(mapcar #'abs '(3 -4 5 -8 -12))
(3 4 5 8 12)    rend la valeur absolue de chaque élément de la liste

(mapcar #'cons '(a b c) '(1 2 3))
((A . 1) (B . 2) (C . 3))     rend une liste de doublets pointés

(mapcar #'(lambda (x) (elt x 0)) '("arbre" "branche" "feuille"))
(#\a #\b #\f)   rend la liste des premières lettres de chaque mot de la
          liste de mots passée en argument

(mapcar #'(lambda (x) (subseq x 1)) '("arbre" "branche" "feuille"))
("rbre" "ranche" "euille")
          rend la liste des mots sans leur première lettre

(mapcar #'(lambda (x) (string x)) '(quote nil eval cons list car cdr append))
("QUOTE" "NIL" "EVAL" "CONS" "LIST" "CAR" "CDR" "APPEND")
              transforme la liste, quotée, de symboles en une liste de chaines de caractères

(sort (mapcar #'(lambda (x) (string x)) '(quote nil eval cons list car cdr append)) #'string<)
("APPEND" "CAR" "CDR" "CONS" "EVAL" "LIST" "NIL" "QUOTE")
        même chose avec rangement par ordre alphanumérique

Voici une fonction qui rend la somme des carrés des nombres passés en argument:

(defun Somme-carrés (&rest nb)
   (multiple-value-call #'+ (values-list (mapcar #'(lambda (x) (* x x)) nb))))

(somme-carrés 9 10 11)
302

Composition de fonctions appliquée à une liste:

(defun mapcompose (fn gn lst)
  (mapcar fn (mapcar gn lst)))

(mapcompose #'(lambda (x) (* 2 x)) #'(lambda (x) (+ x 3)) '(1 2 3))
(8 10 12)   applique la fonction 2(x+3) aux éléments de la liste

(mapcompose #'(lambda (x) (+ x 3)) #'(lambda (x) (* 2 x)) '(1 2 3))
(5 7 9)   applique la fonction 2x+3 aux éléments de la liste

Voici une fonction qui rend la composée de deux fonctions fn et gn à une variable:

(defun composée (fn gn)
  #'(lambda (x) (funcall fn (funcall gn x))))

(functionp #'composée)
T    composée est bien une fonction (de fonction!)

(funcall (composée #'(lambda (x) (+ 5 x)) #'(lambda (x) (* 2 x))) 7)
19 la 2ème fonction λ multiplie x par 2 et la 1ère ajoute 5.
la composée des deux calcule le résultat pour x=7 (donc 2x7+5=19)

(funcall (composée 'acos 'sin) pi)
1.5707963267948966d0 on obtient bien pi/2

MAPLIST:

MAPLIST n'a pas besoin du type rendu comme avec MAP.
Il lui faut la fonction (1er argument), la ou les listes (les autres arguments), elles mêmes arguments de la fonctions.
Rend la liste des résultats de la fonction passée en argument.
MAPLIST s'applique au REST successifs des listes.

(maplist #'append '(a b c d) '(1 2 3) '(e f g))
((A B C D 1 2 3 E F G) (B C D 2 3 F G) (C D 3 G))
      la fonction APPEND est appliquée aux 3 listes, puis au REST des
3 listes, et ainsi de suite jusqu'à ce que l'une des listes soit
vide. Elle rend la liste des résultats.

(maplist #'(lambda (x) (cons 'foo x)) '(a b c d))
((FOO A B C D) (FOO B C D) (FOO C D) (FOO D))
      lambda définie une fonction qui ajoute l'élément foo au début d'une
liste, puis au REST de la liste, et ainsi de suite jusqu'à ce que
la liste soit vide. Elle rend la liste des résultats.

(maplist #'(lambda (x) (if (member (car x) (cdr x)) 0 1)) '(a b a c d b c))
(0 0 1 0 1 1 1)
      lambda définie une fonction qui teste si le premier élément de la
liste passée en argument à MAPLIST est dans le REST de la liste.
lambda rend 0 si oui, 1 sinon. MAPLIST rend la liste des résultats.

(maplist #'(lambda (x) (subseq x 1)) '("arbre" "branche" "feuille"))
(("branche" "feuille") ("feuille") NIL)
      rend la liste des REST successifs de la liste passée en argument

MAPCAN:

(mapcan #'(lambda (x y) (if (null x) nil (list x y))) '(nil nil nil d e) '(1 2 3 4 5 6))
(D 4 E 5)
      rend la liste des résultats (listes) mais concaténés, alors qu'avec
MAPCAR on obtient:

(mapcar #'(lambda (x y) (if (null x) nil (list x y))) '(nil nil nil d e) '(1 2 3 4 5 6))
(NIL NIL NIL (D 4) (E 5))
      donc la liste des listes-résultats.

(mapcan #'(lambda (x) (and (numberp x) (list x))) '(a 1 b c 3 4 d 5))
(1 3 4 5)

(mapcar #'(lambda (x) (and (numberp x) (list x))) '(a 1 b c 3 4 d 5))
(NIL (1) NIL NIL (3) (4) NIL (5))
      même remarque

MAPCON: (de la famille MAPLIST)

(mapcon #'reverse '(1 2 3 4 5))
(5 4 3 2 1 5 4 3 2 5 4 3 5 4 5) rend la liste concaténée (avec NCONC) de (5 4 3 2 1), (5 4 3 2),
                                                        (5 4 3), (5 4) et (5)

(mapcon #'(lambda (x) (format t "~a " (+ 2 (car x)))) '(1 2 3 4 5))
3 4 5 6 7      simple affichage demandé par la fonction lambda qui s'applique à la liste initiale, puis à ses CDR
NIL              MAPCON rend NIL

MAPC: applique son premier argument (une fonction!) à chaque élément de la liste (2ème argument) et des listes suivantes s'il y en a.
      souvent, par nécessité, le premier argument est une fonction avec effet de bord, sinon le 2ème argument est rendu à l'identique.
      (voir le 2ème cas, ci-dessous, avec deux listes)

(defparameter nom '("Julien" "Jean" "Antoine"))
NOM              définition d'une variable nom

nom
("Julien" "Jean" "Antoine")

(mapc #'nstring-upcase nom)
("JULIEN" "JEAN" "ANTOINE") rend le 2ème argument modifié

nom
("JULIEN" "JEAN" "ANTOINE") la variable est modifiée également

Avec deux listes, la fonction doit présenter deux variables:

(mapc #'(lambda (x y) (format t "~a- ~a   " y x)) nom '(1 2 3))
1- JULIEN   2- JEAN   3- ANTOINE   la fonction affiche ce qui est demandé et...
("JULIEN" "JEAN" "ANTOINE")   ...rend le 2ème argument qui, ici, est inchangé

MAPL:

(mapl #'(lambda (x y) (format t "~a ~a   " x y)) '(a b c) '(1 2 3))
(A B C) (1 2 3)   (B C) (2 3)   (C) (3)
(A B C)

prochainement: "ARBRES, ENSEMBLES, TABLES."

Aucun commentaire:

Enregistrer un commentaire