IFT359 – Programmation fonctionnelle Thème #2 Introduction au langage fonctionnel choisi 1 QUELQUES CONCEPTS DE BASE SUR LES LANGAGES DE PROGRAMMATION ET SUR DR-RACKET 2 DrRacket un langage dérivé du λ-calcul • Scheme est un dialecte de Lisp • Lisp a été conçu en 1958 • Scheme a été conçu en 1975 • DrRacket a été conçu en 2009 • DrRacket est un dialecte de Scheme – Les différences sont pour le cours minimes • Lisp est basé sur le λ-calcul • La syntaxe et la sémantique de DrRacket a beaucoup de similarité avec le λ-calcul – abstractions, applications, portée lexicale, typage statique, lambda … – DrRacket ajoute au λ-calcul quelques formes syntaxiques (spéciales), plusieurs librairies et l’évaluation par environnement. • Apprendre à utiliser la syntaxe de DrRacket se fait en quelques heures, c’est la programmation fonctionnelle qui s’acquiert plus lentement parce que c’est une nouvelle façon de penser. 3 DrRacket un langage dérivé du λ-calcul • Langage multi-paradigme mettant l’emphase sur la programmation fonctionnelle • L’évaluation se fait par environnement – Il permet de définir l’affectation – Il facilite le traitement des définitions de fonctions mutuellement récursives. – Pour le moment on peut considérer que l’évaluation par environnement est identique à l’évaluation par substitution. • L’ordre d’évaluation est applicatif – Il est plus performant – En λ-calcul, l’ordre applicatif ne mène pas toujours à la forme normale. – Les construits comme le if et define qui peuvent être problématiques ont une forme spéciale qui ne suivent pas l’ordre applicatif. 4 DrRacket un langage dérivé du λ-calcul • Homoiconicité (code = donnée) • Portée lexicale (statique) des variables • Typage « dynamique » fort – L’interpréteur ou le compilateur infère les types • Offre une Read-Eval-Print-Loop {REPL} • Ramasse-miette {Garbage Collector} 5 Les types d’expression DrRacket • Fonction (Abstraction) – (λ (params …) corps1 corps …) • Application de fonction – (fn-expression args …) • Constante (appelés aussi primitives ou valeurs) • les types primitifs atomiques (booléens, nombres, symboles, caractères…) • les types composés (listes, vecteurs, chaînes de caractères…) • fonctions (appelées aussi opérateurs). – Le but de l’évaluation est la réduction des expressions pour obtenir une constante (on fait abstraction des évaluations pour les effets de bord) • Forme spéciale (appelée aussi forme syntaxique) – ce sont des applications ayant leur propre schéma d’évaluation – plusieurs sont prédéfinies • (if …), (cond …), (define …), (let …) … – elles permettent de simplifier de beaucoup l’écriture des programmes 6 Typage statique versus dynamique Le type d’un identificateur • statique – le type des identificateurs est explicite ou peut être déduit à partir du texte du programme • déverminage plus facile • le compilateur peut générer un code plus efficace • une fonction comme eval est impossible • dynamique – les identificateurs n’ont pas de type • un même identificateur peut être successivement lié à des valeurs de types différents lors de l’exécution d’un programme – les objets (valeurs) ont toujours un type bien définis • l’interpréteur ou le compilateur étiquette automatiquement les objets • identification des opérations menant à une erreur d’exécution avant son exécution. 7 – code plus facilement réutilisable – méta programmation plus simple et expressive Typage fort versus faible détection des erreurs de type Que le typage soit dynamique ou statique, ça ne dit pas ce qu’il faut faire lorsque les types des arguments ne sont pas ceux attendus. • fort – Toutes les opérations exigent que leurs arguments soient du bon type • un message d’erreur est envoyé si ce n’est pas le cas • typage statique : le message est envoyé au moment de la compilation • typage dynamique : le message est envoyé par l’interpréteur • faible – une opération exigeant un argument d’un certain type tentera de le traiter comme s’il était du bon type – cette transformation automatique d’une donnée d’un type dans un autre type (casting) est souvent utile var x := 5; var y := "37"; x + y; ? 8 (x is an integer) (y is a string) 42 ou 537 ou run-time error RACKET ET LAMBDA-CALCUL 11 Abstraction • Abstraction est aussi appelée fonction ou procédure • λ-calcul – λ(xyz)baxy ≡ (λ(x(λ(y)(λ(z)(((ba)x)y)))) • Racket – (λ (x y z) (b a x y)) • les constantes a et b doivent être définies dans l’environnement où cette fonction est définie • dans le texte du programme les valeurs de a et b – doivent être trouver avant l’application de la fonction » doivent faire partie du bloc lexical où apparait la fonction ou d’un bloc lexical parent – peuvent être après ou avant la définition de la fonction 12 Abstraction • Racket – Le corps de la fonction peut avoir plus d’une expression mais seule la dernière est importante pour la sémantique de la fonction. – Toutes les autres expressions (i.e. sauf la dernière) ne sont là que pour les effets de bords, • Dans un langage fonctionnel permettant l’affectation, les effets peuvent être aussi désastreux que dans un langage impératif ou structuré. – (λ (x y z) (+ y z) (print x) (x y z))) • (+ y z) et (print x) n’a aucun impact sur l’exécution de la fonction 13 Application • λ-calcul – (U V W) • Si U se réduit à une abstraction alors (U V W) se simplifie avec la βréduction – ((λ (x y) + x y) 3 4) (+ 3 4) • DrRacket – (U V W) • idem au λ-calcul • U doit s’évaluer comme une abstraction (fonction anonyme) ou une procédure système ou définie par l’usager • ex : ((λ (x y) (+ x y)) 3 4) 7 – (((λ (z) (λ (x y) (z x y))) +) 3 4) la première expression est ((λ (z) (λ (x y) (z x y))) +) et elle n’est pas une abstraction ou une procédure mais une application qui se réduit à une abstraction. 14 Définition • λ-calcul – le terme ≡ • ne fait pas partie du λ-calcul • facilite beaucoup l’écriture des programmes – S ≡ λ(wyx)y(wyx) ;; 3 ≡ λ(sz)s(s(s(z))) – 4 ≡ S 3 • DrRacket – define • permet de créer des liaisons • (define identificateur expression) – (define a 1) – (define b (λ (x) (+ x 4))) – (b a) 5 • n’est pas une fonction mais une forme syntaxique – identificateur n’est jamais évalué • il est possible d’ombrager une liaison existante mais non de la redéfinir 15 – DrRacket ajoute quelques formes syntaxiques et plusieurs définitions Identificateur • Toutes les chaines de caractères en excluant ceux – représentant un nombre • +1, 5.1, 4, 4+i, +nan.0, 2/3, .123 … – contenant un des caractères suivants : ( ) [ ] { } " , ' ` ; # | \ • Exemple – – – – – 16 1.1.1 λ +abc 1+ nan Exécution d’un programme Évaluation par environnement • Un environnement est l’ensemble des liaisons accessibles pour évaluer une expression – Un environnement est un ensemble contenant des paires (identificateur valeur) et pointant possiblement sur un autre environnement appelé environnement parent. • Deux identificateurs différents peuvent pointer sur la même valeur – Il existe un autre dictionnaire reliant les valeurs et les objets • Deux valeurs différentes peuvent pointer sur le même objet • L’imbrication des environnements est parallèle à l’imbrication lexicale • L’environnement racine contient – les identificateurs prédéfinis – les identificateurs définis au premier niveau (top level) 20 Évaluation par environnement d’une fonction • La définition d’une fonction est une paire – La première partie est un pointeur vers l’environnement dans lequel est évaluée la fonction (ne pas confondre avec celui de l’application d’une fonction) – La seconde partie contient • a) les paramètres formels • b) le corps de la fonction • L’environnement dans lequel une fonction est définie est donc conservé avec la fonction pour la durée de la fonction. – i.e tant que la fonction est utilisée ou référencée par un identificateur 21 Exemple d’évaluation d’une fonction Évaluation de (λ (a b) (+ a b)) dans l’environnement initial Environnement Initial Var : a b Corps : (+ a b) 22 Exemple d’évaluation d’une fonction Évaluation de (λ (a b) (+ a b)) dans l’environnement initial Pour simplifier, je vais souvent dessiner l’évaluation de la fonction en dehors de l’environnement Environnement Initial Var : a b Corps : (+ a b) 23 Évaluation par environnement d’une application 1. ((λ (v1 v2 … vn) ff ...) exp1 exp2 ... expn) 2. (λ (v1 v2 … vn) ff ...), exp1 exp2 ... expn sont évalués tel que décrit précédemment 3. Un environnement A est créé et pointe vers l’environnement dans lequel est défini la fonction – voir la première partie de la définition d’une fonction 4. Les identificateurs v1 v2 … vn sont introduits dans l’environnement A et sont associés aux valeurs val1 val2 ... valn 5. Les expressions ff ... sont évaluées dans l’environnement A 24 Exemple d’évaluation d’une application Évaluation de ((λ (a b) (+ a b)) 1 2) dans l’environnement initial Environnement Initial A Var : a b Corps : (+ a b) 25 a:1 b:2 (+ a b) sera évalué dans l’environnement A Évaluation par environnement d’un define Évaluation de (define f (λ (a b) (+ a b)) dans l’environnement initial Environnement Initial f Var : a b Corps : (+ a b) 26 S’il y a plusieurs define dans un programme alors tous les identificateurs sont ajoutés à l’environnement courrant Evaluation de plusieurs define 1. Tous les identificateurs sont ajoutés à l’environnement courant mais ne sont associés à aucune valeur 2. Pour chaque identificateur, on calcule sa valeur et on l’associe à l’identificateur et ce dans l’ordre dans lequel les identificateurs apparaissent 27 • La valeur d’un identificateur dépend de la valeur des identificateurs précédents • Voir les exemples faits avec DrRacket en classe Evaluation par environnement Exercice • Évaluer par environnement les expressions suivantes (define f (λ (a b) (+ a b c))) (define c 7) (define g (λ (c) (f 1 2))) (g 3) – Comparer avec l’évaluation par substitution 28 Initiation au logiciel DrRacket URL du Logiciel http://racket-lang.org/ 29 Choix du langage et de la syntaxe de sortie Ctrl-l + montrer les détails 30 La page de référence sur les types de données LES TYPES PRÉDÉFINIES 31 JE PRÉSENTE PREMIÈREMENT LES TYPES ET ENSUITE LES PROCÉDURES ET LES FORMES SPÉCIALES POUR LES MANIPULER 32 Booléen • Deux valeurs • – #t (true, #T) et #f (false, #F) Toutes les constantes sont considérées vraies mais ce ne sont pas des booléens • • 33 (boolean? 3) #f (if 3 4 5) 4 Nombre • Tous les nombres sont des complexes • 3+2i, 1/3+2.1i … – certains complexes sont des réels • partie imaginaire absente ou égale à 0 • pi, 3.1234, +inf.0, +inf.f, -inf.0, +nan.0 … – certains réels sont des rationnels • tous les réels qui peuvent se représenter comme des float • 1/3, 4.123, (mais pas +inf.0, +inf.f, -inf.0, +nan.0 …) … – certains rationnels sont des entiers • tous les rationnels qui peuvent se représenter de la même façon un fois arrondi à l’entier le plus près • 4.0 4 -0.0 – la taille des entiers n’a pas de limite sauf celle de la mémoire – de même pour les entiers utilisés pour représenter une fraction • Il y a plusieurs prédicats pour caractériser les nombres – voir diapositives 47 34 Caractère • Ce sont des caractères unicode • la chaine « #\ » annonce un caractère – #\A et #\u0041 réfèrent au caractère A – #\λ et #\u03BB réfèrent au caractère λ – dans #\uXXXX, le XXXX est la valeur unicode du caractère en hexadécimal (voir http://www.unicodemap.org/) – certains caractères ont une forme spéciale • #\space espace • #\newline retour de chariot • voir la liste à la section 12.6.13 du fichier 35 Symbole • Un symbole est une valeur atomique qui n’a pas d’équivalent dans la majorité des langages. – Très utilisé dans le traitement symbolique, par exemple faire un programme en mesure de faire de l’intégration symbolique. – Un symbole s’affiche comme un identificateur précédé d’un ‘. – Les symboles ont une représentation unique. • deux symboles qui ont le même nom sont identiques – ils sont le même objet et occupent le même espace dans la mémoire • 2 chaînes de caractères identiques peuvent être deux objets distincts et référer à des espaces différents dans la mémoire – Les symboles apparaissent comme des identificateurs mais ils n’en sont pas – La forme syntaxique quote (') permet de créer un symbole 36 • • • • (quote a) a ' a a (quote left) left 'λ -> λ Vecteur • DrRacket traites les vecteurs de façon similaire aux principaux langages de programmation • se code comme une liste précédé par # • #(1 2 3) • s’affiche comme une liste précédé par ‘# • ‘#(1 2 3) 37 Chaîne de caractères • DrRacket traites les chaînes de caractère de façon similaire aux principaux langages de programmation – similaire à un vecteur de caractère • mais c’est un type à part entière • il se code et s’affiche de façon distincte • "ag\nfkldjlf" 38 Paire • Identique à la notion de paire en mathématiques • Réunit dans une structure deux objets quelconques • Une paire réunissant obj1 et obj2 se code et s’affiche comme ‘(obj1 . obj2) 39 Liste • Une chaîne de paires de la forme '(o1 . (o2 . --- . (on . ())---)) que l’on écrit généralement sous la forme '(o1 o2 --- on) • Exemple '(1 . (2 . (3 . (4 . ())))) qui s’affiche comme ‘(1 2 3 4) • La chaîne de paires peut être vide et nous obtenons la liste de vide que l’on note ‘() ou null • Attention – la liste vide n’est pas une paire – une liste propre se termine toujours par la liste vide – mais on peut faire des listes impropres 40 Autres types prédéfinis • • • • • • • • • • • 41 Byte Strings Regular Expressions Keywords Mutable Pairs and Lists Boxes Hash Tables Sequences and Streams Dictionaries Sets Procedures (déjà vus, ce sont les (λ …)) Void and Undefined QUELQUES PROCÉDURES DÉFINIES SUR LES TYPES PRIMITIFS 42 Booléens • (boolean? v) → boolean? v : any/c • (not v) → boolean? v : any/c • (immutable? v) → boolean? – V est immutable? s’il est un objet de type string ou vector immutable – Attention les listes et les paires sont normalement immutables – J’utilise peu ce prédicat 43 Booléens • (equal? v1 v2) → boolean? v1 : any/c v2 : any/c – v1 et v2 sont equal? s’ils sont eqv? sauf s’ils sont des éléments composés, ces derniers ont un traitement spécial • (eqv? v1 v2) → boolean? v1 : any/c v2 : any/c – v1 et v2 sont eqv? s’ils sont eq? sauf pour les caractères et les nombres ces derniers ont un traitement spécial • (eq? v1 v2) → boolean? Il existe aussi plusieurs prédicats spécialisés (char=?, char<? …), les nombres (=, < …), les string (string=?, string<? …)… v1 : any/c v2 : any/c – v1 et v2 sont eq? s’ils réfèrent au même objet 44 Les nombres Procédures prédicats =, <, <=, >, >= number? complex? real? rational? integer? zero? positive? negative? even? odd? exact? inexact? equal? ≠ = 45 +, -, *, / abs max min gcd lcm sqrt expt exp log sin cos tan asin acos atan Il y en plusieurs autres voir ce fichier quotient remainder modulo inexact->exact exact->inexact make-rectangular make-polar real-part imag-part magnitude angle round floor ceiling truncate numerator denominator rationalize Caractères Prédicats char? char=? char<? char<=? char>? char>=? char-ci=? char-ci<? char-ci<=? char-ci>? char-ci>=? 46 voir ce fichier Procédures char-alphabetic? char-lower-case? char-upper-case? char-title-case? char-numeric? char-symbolic? char-punctuation? char-graphic? char-whitespace? char-blank? char-iso-control? char->integer integer->char char-utf-8-length char-general-category make-known-char-range-list char-upcase char-downcase char-titlecase char-foldcase Symbole symbol? symbol->string string->symbol Vous utiliserez beaucoup les symboles dans ce cours mais la majorité du temps avec des procédures plus générales ou en lien avec d’autres stuctures de données : (eq? s1 s2) (member s1 listedesymboles) (cons s1 listedesymbole) (car listedesymbole) …. 47 voir ce fichier Vecteur vector? make-vector vector vector-length vector-ref vector->list list->vector vector->values build-vector vector-map vector-append vector-take vector-take-right vector-drop vector-drop-right vector-split-at vector-split-at-right vector-copy vector-filter vector-filter-not vector-count vector-argmin vector-argmax vector-member vector-memv vector-memq vector->immutable-vector Attention plusieurs des procédures mentionnées manipulent ou créent des vecteurs mutables Les vecteurs retournés par le reader sont immutables 48 voir ce fichier Chaîne de caractères Procédures make-string string string-length string-ref substring string-copy string-append string->list list->string string->immutable-string string-set! Prédicats build-string string-upcase string-downcase string-titlecase string-foldcase string-locale-upcase string-locale-downcase string-append* string-join string-copy! string-fill! string? string=? string<? string<=? string>? string>=? string-ci=? string-ci<? string-ci<=? string-ci>? string-ci>=? Attention la majorité des procédures mentionnées manipulent ou créent des chaînes de caractères mutables Les chaînes de caractères retournées par le reader sont immutables 49 voir ce fichier Paires • (cons a b) crée une paire (define x (cons 'a 'b)) (a . b) (define y (cons 'a (cons 'b '()))) (a . (b . ()) = (a b) (define z (cons 1 y)) (1 . (a . (b . ()))) = (1 a b) 50 Paires • (car x) retourne la valeur dans la première cellule d’une paire (car (1 . 2)) 1 (define z (cons 1 (cons ‘a (cons ‘b ())))) (1 a b) (car z) 1 • (cdr x) retourne la valeur dans la deuxième cellule d’une paire (cdr (1 . 2)) 2 (cdr z) (a b) • (pair? x) ou (cons? x) 51 Listes null? empty? cons car cdr null list? list list* build-list length list-ref list-tail append reverse map andmap 52 ormap for-each foldl foldr filter remove remq remv remove* remq* remv* sort member memv memq memf findf voir ce fichier assoc assv assq assf caar cadr cdar cddr c...ar c...dr first rest second third fourth fifth sixth seventh eighth ninth tenth last last-pair make-list take drop split-at take-right drop-right split-at-right add-between append* flatten filter-map remove-duplicates count partition append-map filter-not shuffle argmin argmax make-reader-graph placeholder? make-placeholder placeholder-set! placeholder-get hash-placeholder? make-hash-placeholder make-hasheq-placeholder make-hasheqv-placeholder Ceux en rouge sont à connaître Listes • Vous travaillerez beaucoup avec les listes 53