Scheme

publicité
Programmation fonctionnelle
Plan:
Lisp
Un Resumé du Scheme
Une session Scheme
Scheme:
Structures de données simples
Structures de données composées
Évaluation de fonctions
Construction de listes et accès aux éléments
Expressions fonctionnelles et définition de fonctions
contrôle
Fonctions de haut niveau
CSI 3125, Scheme, page 1
Lisp
• La programmation fonctionnelle a commencé vers
la fin des années 1950 (Veuillez relire la section
2.4). Plusieurs dialectes, Lisp 1.5 (1960), Scheme
(1975), Common Lisp (1985)…[LISP = LISt Processor]
• [Il y a aussi d’autre langages fonctionnels: Hope,
ML, Miranda, Haskell.]
• Plusieurs langages fonctionnels (dont Lisp) ont
comme fondation mathématique le -calcul
(lambda-calcul), un système qui permet aux
fonctions d’être les valeurs d’une expression.
CSI 3125, Scheme, page 2
Lisp (2)
• Mécanismes de control fondamentaux:
– Application de fonctions
– Composition de fonctions
– Instructions conditionnelles
– récursivité
• Les structures de données sont simples:
– listes,
– atomes (symboles et nombres).
CSI 3125, Scheme, page 3
Lisp (3)
• Les programmes et données sont exprimés à l’aide de la
même syntaxe:
– L’application de fonctions et les instructions
conditionnelles sont écrites comme des listes, en
parenthèse, avec le nom de l’instruction comme préfixe.
– Le programme et les données sont distinguées selon le
contexte.
• Cette uniformité des données et du programme permettent
une grande flexibilité et expressivité:
– Les programmes peuvent être manipulés comme des
données.
• Un interpréteur de LISP d’ une page en LISP a été à la base
de la première implémentation en bootstrapping d’un
langage de programmation (une technique très puissante)
CSI 3125, Scheme, page 4
Lisp (4)
5 fonctions primitives:
• cons
—
construit une liste,
• car
—
la tête d’une liste,
• cdr
—
la queue d’une liste,
• eq
—
Égalité d’atomes (Booléenne),
• atom
—
Vérifie si une atome (Booléenne);
• Deux autres opérations essentielles:
– L’évaluation d’expressions,
– Appliquer une fonction aux paramètres (déjà
évalués)
CSI 3125, Scheme, page 5
Lisp (5)
• Lisp est utilisé de façon interactive (comme Prolog):
– Aucun programme principal,
– L’interpréteur évalue les expressions et retourne leur
valeur (les expressions peuvent invoquer des fonctions
très compliquées),
– Un programme Lisp est une collection de fonctions qui
peuvent être invoquées directement ou indirectement par
l’interpréteur.
– Toute expression est évaluée: Il faut dire explicitement à
Lisp de ne pas évaluer quelque chose (avec quote)
• Un atome est traité littéralement: il n’est que lui même et n’a
d’autre valeur que son nom.
CSI 3125, Scheme, page 6
Lisp (6)
Lisp 1.5 à plusieurs points faibles:
• Syntaxe peu commode (mais élégante et
uniforme).
• Règles à porté dynamique [Que nous verrons
plus tard]
• Traitement inconsistant des fonctions en tant
que paramètres (due à la porté dynamique).
CSI 3125, Scheme, page 7
Un Resumé du Scheme
• Scheme est un sous-ensemble de Lisp.
• Il fait la distinction entre nombres et symboles
• La porté est lexicale (plutôt que dynamique)
• Corrige le problème du traitement des paramètres
(grâce à la porté lexicale):
– Les fonctions sont des objets de première classe, c’est à
dire qu’elles peuvent être créées, assignées à des
variables, passées comme paramètres, retournées
comme valeurs.
• Les structures de données, en Scheme sont simples,
uniformes et versatiles. Comme pour Lisp 1.5, on les
appelles S-expressions.
CSI 3125, Scheme, page 8
Le system Scheme pour ce cours
Veuillez vous connecter (via ssh) a site1, et taper scm au prompt.
% scm
SCM version 5d3, Copyright (C) 1990-1999 Free Software Foundation.
SCM comes with ABSOLUTELY NO WARRANTY; for details type `(terms)'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `(terms)' for details.
;loading /usr/local/lib/slib/require
;done loading /usr/local/lib/slib/require.scm
;loading /usr/local/lib/scm/Transcen
;done loading /usr/local/lib/scm/Transcen.scm
;Evaluation took 50 mSec (0 in gc) 15992 cells work, 4000 env,
17604 bytes other
>
A ce moment la, vous êtes en dialogue avec la boucle interactive
supérieure. Vous pouvez, par example, taper (terms) ou (exit) ou (quit)
ou vous pouvez continuer…
CSI 3125, Scheme, page 9
Une session Scheme
% scm
> ( cons 'alpha '( beta ) )
(alpha beta)
> ( symbol? 'alpha )
#t
> ( symbol? '( alpha ) )
#f
CSI 3125, Scheme, page 10
Une session Scheme(2)
> ( null? 'alpha )
#f
> ( null? () )
#t
> ( number? 'alpha )
#f
> ( number? 23 )
#t
> ( symbol? alpha )
ERROR: unbound variable: alpha
; in expression: (... alpha)
; in top level environment.
CSI 3125, Scheme, page 11
Une session Scheme (3)
> ( define alpha 5 )
#<unspecified>
> ( number? alpha )
#t
> ( symbol? alpha )
#f
> ( cdr ( cons 'x '( y z ) ) )
(y z)
> ( cons 'x ( cdr '( y z ) ) )
(x z)
> ( + 1 2 )
3
CSI 3125, Scheme, page 12
Une session Scheme(4)
> ( define ( addOne x )
( + x 1 )
)
#<unspecified>
> ( addOne ( addOne 15 ) )
17
> ( define ( myAnd x y )
( if x y #f )
)
#<unspecified>
> ( myAnd ( symbol? '(a) ) ( eq? 'a 'a ) )
#f
> ( and ( symbol? '(a) ) ( eq? 'a 'a ) )
#f
CSI 3125, Scheme, page 13
Une session Scheme(5)
> ( define ( myOr x y )
( if x #t y )
)
#<unspecified>
> ( myOr ( symbol? '(a) ) ( eq? 'a 'a ) )
#t
> ( or ( symbol? '(a) ) ( eq? 'a 'a ) )
#t
> ( eq? 'a 'a )
#t
> ( eq? 'a 'b )
#f
> ( eq? '( a ) '( a ) )
#f
CSI 3125, Scheme, page 14
Une session Scheme(6)
>
( define ( numberList? x )
( if ( not ( list? x ) )
#f
( if ( null? x )
#t
( if ( not ( number? ( car x ) ) )
#f
( numberList? ( cdr x )
) )
)
)
)
#<unspecified>
> ( numberList? ' ( 1 2 3 4 ) )
#t
CSI 3125, Scheme, page 15
Une session Scheme (7)
>
( define ( numberList? x )
( cond
( ( not ( list? x ) ) #f )
( ( null? x ) #t )
( ( not ( number? ( car x ) ) ) #f )
( else ( numberList? ( cdr x ) ) )
) )
> ( numberList? ' ( 1 2 3 4 ) )
#t
> ( numberList? ' ( 1 2 3 bad 4 ) )
#f
CSI 3125, Scheme, page 16
Une session Scheme (8)
>
( define ( eqExpr? x y )
( cond
( ( symbol? x ) ( eq? x y ) )
( ( number? x ) ( eq? x y ) )
; x must be a list now:
( ( null? x ) ( null? y ) )
; x must be a non-empty list now:
( ( null? y ) #f )
( ( eqExpr? ( car x ) ( car y ) )
( eqExpr? ( cdr x ) ( cdr y ) ) )
( else #f )
) )
> ( eqExpr?
#t
> ( eqExpr?
#f
'( a b ( c d ) )
'( a b ( c d ) )
'( a b ( c d ) )
'( a b ( c d e) )
)
)
CSI 3125, Scheme, page 17
Une session Scheme (9)
> ( define ( member? K L )
( cond
( (null? L ) #f )
( ( eqExpr? K ( car L ) ) #t )
( else ( member? K ( cdr L ) ) )
) )
#<unspecified>
> ( member? 'aa '( bb cc aa ee rr tt ) )
#t
> ( member? 'aa '( bb cc (aa) ee rr tt ) )
#f
CSI 3125, Scheme, page 18
Une session Scheme (10)
> ( define ( append L1 L2 )
; built-in!
(if ( null? L1 )
L2
( cons ( car L1 )
( append ( cdr L1 ) L2 ) )
) )
WARNING: redefining built-in append
#<unspecified>
> ( append '( ab bc cd )
'( de ef fg gh ) )
(ab bc cd de ef fg gh)
> ( exit )
;EXIT
CSI 3125, Scheme, page 19
Structures de données simples
• Nombres: entiers ou floats.
• Une variable est un nom lié à une donnée, par exemple:
(define pi 3.14159)
• Une variable a un type implicite, dépendant de sa valeur.
Elle peut prendre une valeur d’un autre type:
(set! pi 3.141592)
(set! pi 'alpha)
(set! pi (cons pi '(rho)))
• Un symbole est un nom n’ayant d’autre valeur que lui
même.
CSI 3125, Scheme, page 20
Structures de données composées
Le format générale d’une liste:
(E1 E2 ...... En) où Ei est une S-expression.
Dépendamment du contexte, une liste peut être traité
littéralement (comme une donnée):
((William Shakespeare)
(The Tempest))
ou comme une application de fonction avec les
paramètres passés par valeur:
(append x y)
CSI 3125, Scheme, page 21
Structures de données composées (2)
Une liste (E1 E2 ...... En) est produite par cons:
(cons E1 (cons E2 ... (cons En ()) ... ))
produit:
(E1 . (E2 ... (En . ( )) ... ))
On a aussi les paires ‘pointées’, peu utilisées en pratique:
cons( )
produit:
( . )
CSI 3125, Scheme, page 22
Évaluation de fonctions
• Avec: une liste (E0 E1 ... En)
• Étape 1
Évalue E0 pour obtenir V0,
Évalue E1 pour obtenir V1,
......,
Évalue En pour obtenir Vn.
V0 doit être une fonction,
V1, ..., Vn sont des données.
• Étape 2
Applique V0 à V1, ..., Vn
C’est à dire, calcule V0(V1, ..., Vn).
CSI 3125, Scheme, page 23
Quote
• L’évaluation est bloquée par quote:
(quote pi) ou de façon équivalente: 'pi
• Si pi est défini ainsi:
(define pi 3.141592)
• Exemples:
(* 2.0 pi)
retourne 6.283184
(* 2.0 'pi)
paramètre invalide
('* 2.0 'pi)
fonction invalide
(write 'pi)
affiche le symbole pi
(write pi)
affiche 3.141592
CSI 3125, Scheme, page 24
Construction de listes et accès aux éléments
• Les listes sont définies récursivement:
Une liste vide: (),
Une liste non-vide: (cons  x)
où x is a list.
• La tête et la queue d’une liste:
(car (cons  x)) retourne 
(cdr (cons  x)) retourne x
(car ()) et (cdr ()): paramètre invalide
CSI 3125, Scheme, page 25
Accès aux éléments
Une convention de notation pour accéder aux autres éléments
de la liste:
(caar x)  (car (car x))
(cdadr x)  (cdr (car (cdr x))))
Par exemple, l’évaluation suivante se fait en 4 étapes:
(caadar '((p ((q r) s) u) (v)))
(caadr '(p ((q r) s) u))
(caar '(((q r) s) u))
(car '((q r) s))
'(q r)
Le deuxième élément d’une liste x — si il existe:
(cadr x)
Le troisième, quatrième, ... :
(caddr x), (cadddr x), ...
CSI 3125, Scheme, page 26
Fonctions primitives
• car, cdr, cons sont les fonctions primitives qui
permettent l’accès aux listes. Trois autres sont des
prédicats: des fonctions qui retournent #t ou #f.
• (symbol? x)
#t ssi x est un symbole symboles,
• (number? x)
– ssi x est un nombre,
• (eq? x y)
– ssi x et y sont des symboles et sont égaux.
CSI 3125, Scheme, page 27
Autre fonctions
Autre fonctions
(elle peuvent être définie à partir des primitives):
(equal? x y) vrai ssi x et y sont des objets
identiques (pas nécessairement atomique)
(null? x) si x est () – la liste vide.
(append x y) concatène les listes x et y.
CSI 3125, Scheme, page 28
Définir des fonctions
Une définition lie l’expression d’une fonction à un nom:
(define (square x) (* x x))
ou, de façon équivalente:
(define square
(lambda (x) (* x x)))
Le nom d’une fonction peut être évaluée:
> square
#<CLOSURE (x) #@lambda (* x x)>
Les fonctions n’ont pas nécessairement de nom!
> ((lambda (x) (* x x x)) 3)
27
CSI 3125, Scheme, page 29
Contrôle
Les structures de contrôle en Scheme, comme en
Lisp, sont simple. Il n’existe pas de boucles. Il y a
l’application de fonctions, l’expression conditionnelle,
et la séquence (une concession aux programmeurs
habitués aux langages impératifs):
> (begin (print 'okay) (print '(great)))
okay
(great)
;Evaluation took [...]
(great)
La valeur retournée par (begin ...) est la valeur du
dernier terme.
CSI 3125, Scheme, page 30
Instructions conditionnelles
(cond (C1 E1)
(C2 E2) ......
(Cn En)
(else En+1))
• La dernière partie, (else En+1), est optionnelle.
• (Ci Ei) représente une paire condition-expression. Les pairs
sont évaluées de gauche à droite. On arrête quand on trouve
un Ci qui est vrai (qui retourne #t ). On retourne le Ei
correspondant.
• else est évalué comme #t.
CSI 3125, Scheme, page 31
Cas spécial: if
(cond (C1 E1) (else E2))
Peut être abrégé:
(if C1 E1 E2)
CSI 3125, Scheme, page 32
D’autre exemples de fonctions
(define (same_neighbours? l)
(cond
((null? l) #f)
((null? (cdr l)) #f)
((equal? (car l)(cadr l)) #t)
(else
(same_neighbours? (cdr l)))
) )
CSI 3125, Scheme, page 33
Pile en Scheme
(define (empty? stack)
(null? stack)
)
(define (push el stack)
(cons el stack)
)
(define (pop stack)
(if (empty? stack)
stack
(cdr stack)
) )
(define (top stack)
(if (empty? stack)
()
(car stack)
) )
CSI 3125, Scheme, page 34
Minimum d’une liste
(define (minL Lst)
(if (null? Lst)
Lst
(minL-aux (car Lst)(cdr Lst))
) )
(define (minL-aux Elt Lst)
(cond
((null? Lst) Elt)
((> Elt (car Lst))
(minL-aux (car Lst)(cdr Lst)))
(else (minL-aux Elt (cdr Lst)))
) )
CSI 3125, Scheme, page 35
Minimum d’une liste, une variante a porte locale
(define (minL-aux Elt Lst)
(if (null? Lst)
Elt
(let
((carl (car Lst))
(cdrl (cdr Lst)))
(if
(> Elt carl)
(minl-aux carl cdrl)
(minl-aux Elt cdrl)
) )
) )
CSI 3125, Scheme, page 36
Un autre exemple de portée
locale
>
(define (quadruple x)
(let ((double (lambda (x) (+ x x))))
(double (double x))
) )
#<unspecified>
> (quadruple 8)
32
> (double 8)
unbound variable: double
; in expression: (... double 8)
; in top level environment.
CSI 3125, Scheme, page 37
Un autre exemple de portée
locale (2)
>
(define (quadruple x)
(define (double x) (+ x x))
(double (double x))
)
#<unspecified>
> (quadruple 8)
32
> (double 8)
unbound variable: double
; in expression: (... double 8)
; in top level environment.
CSI 3125, Scheme, page 38
Fonctions de haut-niveau
Certaine fonctions prennent des fonctions comme paramètres.
> (define (combine Fun1 Fun2 X)
(Fun1 (Fun2 X))
)
> (combine (lambda (x) (+ 1 x))
(lambda (x) (* 2 x))
6)
> (combine (lambda (x) (* 2 x))
(lambda (x) (+ 1 x))
6)
Équivalent à:
> ((lambda (x) (+ 1 x)) ((lambda (x) (* 2 x)) 6))
> ((lambda (x) (* 2 x)) ((lambda (x) (+ 1 x)) 6))
CSI 3125, Scheme, page 39
Fonctions de haut-niveau (2)
Un exemple classique: map, l’opération qui applique
une fonction aux éléments d’une liste:
(E1 E2 ...... En)  ((f E1) (f E2) ...... (f En))
(define (map F Lst)
(if (null? Lst)
Lst
(cons (F (car Lst))
(map F (cdr Lst)))
) )
Par exemple (map (lambda(x) (+ x 1)) '(1 2 3))
retourne: (2 3 4)
CSI 3125, Scheme, page 40
Fonctions de haut-niveau (3)
Une version de map qui applique la fonction à chaque éléments
sans retourner la liste résultante:
(define (do-for-all F L)
(if (null? L)
L
(let ((dummy (F (car L))))
(do-for-all F (cdr L))
) ) )
Par exemple:
(do-for-all write '(1 2 3))
CSI 3125, Scheme, page 41
Fonctions de haut-niveau (4)
Voici un petit exercice:
(define (f) (lambda (x) (+ 1 x)))
Quelle est la valeur de cette fonction?
CSI 3125, Scheme, page 42
Réducteurs
Soit F une opération binaire, c’est à dire, à deux
paramètres. Soit F0 une constante. On veut exprimer la
transformation suivante:
(E1 E2 ...... En) 
(F E1 (F E2 (F ...... (F En F0) ...... )))
Qui s’exprime plus facilement avec une notation infixe:
(E1 E2 ...... En)  E1 F E2 F ...... F En F F0
CSI 3125, Scheme, page 43
Reducteurs (2)
Example:
(E1 E2 ...... En)  E1 + E2 + ...... + En + 0
(E1 E2 ...... En)  E1 * E2 * ...... * En * 1
(define (reduce F F0 L)
(if (null? L)
F0
(F (car L)
(reduce F F0 (cdr L)))
) )
CSI 3125, Scheme, page 44
Reducers (3)
> (reduce + 0 '(1 2 3 4))
> (reduce * 1 '(1 2 3 4))
> (reduce (lambda (x y) (+ x y 1))
8 '(1 2 3))
> (reduce cons () '(1 2 3 4))
> (reduce append () '((1) (2) (3)))
CSI 3125, Scheme, page 45
Noms pre-determines
Manipulation de liste
Pour définir
car
define
cdr
lambda
cons
append
list
length
caar, cadr, cdar, cddr,
...,
caaaar, ..., cddddr
CSI 3125, Scheme, page 46
Noms pré-determinés (2)
Contrôle
Logique
if
cond
else
let
begin
not
and
or
#t
#f
Arithmétique et comparaison
+
*
/
max
min
<
>
<=
>=
=
CSI 3125, Scheme, page 47
Noms pré-déterminés (3)
Prédicats
symbol?
number?
integer?
real?
list?
null?
eq?
equal?
procedure?
fonctions I/O
write
display
print
read
Divers
load
map
quote
set!
CSI 3125, Scheme, page 48
Téléchargement