Algorithmique et Programmation Fonctionnelle (APF) Algorithmique et Programmation Fonctionnelle (APF) RICM3 Cours 6 : Flots Jean-François Monin Polytech 2013 - 2014 1/5 Algorithmique et Programmation Fonctionnelle (APF) La dernière fois I Type unit, effets de bord I Analyse syntaxique sur des listes 2/5 Algorithmique et Programmation Fonctionnelle (APF) Plan Fonction d’ordre supérieur 3/5 Algorithmique et Programmation Fonctionnelle (APF) Flots Plan Fonction d’ordre supérieur 4/5 Algorithmique et Programmation Fonctionnelle (APF) Flots Flots (Stream) Structure séquentielle polymorphe paresseuse I séquentielle polymorphe : comme les listes I paresseuse : construite à mesure des demandes de consommation (activation d’un filtrage) I consommée (détruite) à mesure qu’elle est analysée Intérêts I éviter la construction d’une grosse structure de données intermédiaire I I typiquement : fichier vu comme flot de caractères. . . transformé en flot de lexèmes I facilités d’expression : parser I ⇒ utilisation idéale dans les analyseurs récursifs descendants Exemple : Pascal -> Caml, compilation, etc ... 5/5 Algorithmique et Programmation Fonctionnelle (APF) Flots Consommation Idée : consommer peu de mémoire en ne travaillant que sur une fenêtre glissante de la donnée à analyser. Avantages et inconvénients I Bonne discipline de programmation forcée par l’utilisation des flots I Impossibilité de revenir en arrière Comment faire ? I Utiliser des arguments supplémentaires pour conserver les données issues du passé I Conception de la grammaire : partager les préfixes communs 6/5 Algorithmique et Programmation Fonctionnelle (APF) Flots Flots : construction Extension syntaxique requise : #load "dynlink.cma" ; ; #load "camlp4o.cma" ; ; Constructeurs I Stream.from, Stream.of_string, Stream.of_channel I [< ... >] Ne pas mélanger ces 2 constructeurs # let flux_int_19 =[<’1; ’9>];; val flux_int_19 : int Stream.t = <abstr> # let flux_char_ab =[<”a’; ”b’>];; val flux_char_ab : char Stream.t = <abstr> #let flux_char_ab_cd = [< flux_char_ab; flux_char_cd>];; #let flux_char_1934 = Stream.of_string "1934";; 7/5 Algorithmique et Programmation Fonctionnelle (APF) Flots Flots : production paresseuse # let rec nat_stream n = [< ’n ; nat_stream (n+1) >] ;; val nat_stream : int -> int Stream.t = <fun> # let nat = nat_stream 0 ;; val nat : int Stream.t = <abstr> 8/5 Algorithmique et Programmation Fonctionnelle (APF) Flots Utilisation (analyse) d’un flot : avec “consommation” 9/5 Algorithmique et Programmation Fonctionnelle (APF) Flots Utilisation (analyse) d’un flot : avec “consommation” Récupération du premier élément d’un flot #let next s = match s with parser [< ’x >] -> x ;; Exemple : # # - next nat;; : int = 0 next nat;; : int = 1 9/5 Algorithmique et Programmation Fonctionnelle (APF) Flots Utilisation (analyse) d’un flot Le motif de filtrage concerne le début du flot 10 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Utilisation (analyse) d’un flot Le motif de filtrage concerne le début du flot Un motif peut contenir des constantes 10 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Utilisation (analyse) d’un flot Le motif de filtrage concerne le début du flot Un motif peut contenir des constantes Un motif peut mentionner d’autres analyseurs de flot Notation : résultat = analyseur (comme si on avait un let, omis par souci de concision) 10 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Utilisation (analyse) d’un flot Le motif de filtrage concerne le début du flot Un motif peut contenir des constantes Un motif peut mentionner d’autres analyseurs de flot Notation : résultat = analyseur (comme si on avait un let, omis par souci de concision) On peut choisir entre plusieurs motifs 10 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Utilisation (analyse) d’un flot Le motif de filtrage concerne le début du flot Un motif peut contenir des constantes Un motif peut mentionner d’autres analyseurs de flot Notation : résultat = analyseur (comme si on avait un let, omis par souci de concision) On peut choisir entre plusieurs motifs Un motif peut contenir une séquence de motifs séparés par ’ ;’ (consommés en tête du flot analysé) 10 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Utilisation (analyse) d’un flot Le motif de filtrage concerne le début du flot Un motif peut contenir des constantes Un motif peut mentionner d’autres analyseurs de flot Notation : résultat = analyseur (comme si on avait un let, omis par souci de concision) On peut choisir entre plusieurs motifs Un motif peut contenir une séquence de motifs séparés par ’ ;’ (consommés en tête du flot analysé) Cas du motif vide [< >] : toujours accepté 10 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Grammaire correspondant à un analyseur de flot Une fonction d’analyse correspond à un non-terminal : consommation de ce non-terminal en début de flot 11 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Grammaire correspondant à un analyseur de flot Une fonction d’analyse correspond à un non-terminal : consommation de ce non-terminal en début de flot Le motif de flitrage à l’intérieur de [< ... >] correspond au membre droit d’une règle 11 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Grammaire correspondant à un analyseur de flot Une fonction d’analyse correspond à un non-terminal : consommation de ce non-terminal en début de flot Le motif de flitrage à l’intérieur de [< ... >] correspond au membre droit d’une règle Même idée que pour l’analyse de listes, avec les différences suivantes I on ne s’encombre pas avec la liste (le flot) en cours d’analyse, il est implicitemment présent I plus grande facilité pour exprimer les choix (inutile de calculer le premier terminal qui pilote le choix) I effet de bord : on ne revient pas sur un terminal consommé 11 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Flots : profondeur de parenthèses let rec profond = parser [< ’’(’; n=profond ; ’’)’; >] -> n+1 | [<>] -> 0;; let tata = Stream.of_string "(((())))" ;; let qq = profond tata;; 12 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Flots : profondeur de parenthèses let rec profond = parser [< ’’(’; n=profond ; ’’)’; >] -> n+1 | [<>] -> 0;; let tata = Stream.of_string "(((())))" ;; let qq = profond tata;; Avec accumulateur 12 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Flots : profondeur de parenthèses let rec profond = parser [< ’’(’; n=profond ; ’’)’; >] -> n+1 | [<>] -> 0;; let tata = Stream.of_string "(((())))" ;; let qq = profond tata;; Avec accumulateur let rec profond_a n = parser | [<’’(’; p = profond_a (n+1); ’’)’;>] -> p | [<>] -> n 12 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Construction d’un flot à partir d’un flot en entrée Étant donné un flux de caractères s, construire un flot identique à s mais sans ses voyelles 13 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Construction d’un flot à partir d’un flot en entrée Étant donné un flux de caractères s, construire un flot identique à s mais sans ses voyelles let rec otervoy s = match flux with parser | [< ’ (’a’|’e’|’i’|’o’|’u’|’y’) >] -> otervoy s | [<’x>] -> [<’x; otervoy s>] 13 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Flot de parenthèses Grammaire I P := (P) I P := a Écrire une fonction qui enleve les parenthèses de ce flot. solution 14 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Flot de parenthèses Grammaire I P := (P) I P := a Écrire une fonction qui enleve les parenthèses de ce flot. solution let rec oterparenth flux = match flux with parser [< ”(’ ; s= oterparenth ; ”)’ ; >] -> s | [< ’ x >] -> [<’x ; oterparenth flux>] ; ; 14 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Flot de caractères → flot de lexèmes let rec next_tok = parser | [<’ 0 0 ; tk = next_tok >] → tk | [<’ 0 +0 >] → Some (Tplus) | [<’ 0 00 ..0 90 as c ; >] → Some (Tent (horner (valchiffre c))) . | .. | [< >] → None let lex s = Stream.from (fun _ → next_tok s) avec les bons types. 15 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Exemple Considèrons la grammaire suivante : S ::= P S | a P ::= ( S ) | x 16 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Exemple Considèrons la grammaire suivante : S ::= P S | a P ::= ( S ) | x let rec a_S = parser | [< ok1 = a_P ; ok2 = a_S >] → () | [< ’ 0 a 0 >] → () and a_P = parser | [< ’ 0 (0 ; ok = a_S ; ’ 0 )0 >] → () | [< ’ 0 x 0 >] → () D’une manière générale, les fonctions comme a_P rendent un résultat, par exemple (), 16 / 5 Algorithmique et Programmation Fonctionnelle (APF) Flots Compilation Utiliser l’option -pp de ocamlc pour créer le .cmo ocamlc -pp "camlp4o pa extend.cmo" -I +camlp4 -c fichier.ml puis on compile avec ocamlc fichier.cmo -o nom executable. Documentation http: //caml.inria.fr/pub/oldcamlsite/camlp4/index.html 17 / 5 Algorithmique et Programmation Fonctionnelle (APF) Fonction d’ordre supérieur Plan Fonction d’ordre supérieur 18 / 5 Algorithmique et Programmation Fonctionnelle (APF) Fonction d’ordre supérieur fold * Ecrire une fonction qui calcule le résultat d’une fonction appliquée successivement à l’ensemble des termes d’une liste. 19 / 5 Algorithmique et Programmation Fonctionnelle (APF) Fonction d’ordre supérieur fold * Ecrire une fonction qui calcule le résultat d’une fonction appliquée successivement à l’ensemble des termes d’une liste. Solution 19 / 5 Algorithmique et Programmation Fonctionnelle (APF) Fonction d’ordre supérieur fold * Ecrire une fonction qui calcule le résultat d’une fonction appliquée successivement à l’ensemble des termes d’une liste. Solution let rec fold f accu = function | [ ] -> accu | a : : l -> fold f (f accu a ) l ; ; let let let let plus x y = x+y ; ; addition = fold plus 0 ; ; fois x y = x * y ; ; multiplication = fold fois 1 ; ; 19 / 5 Algorithmique et Programmation Fonctionnelle (APF) Fonction d’ordre supérieur fold * Ecrire une fonction qui calcule le résultat d’une fonction appliquée successivement à l’ensemble des termes d’une liste. Solution let rec fold f accu = function | [ ] -> accu | a : : l -> fold f (f accu a ) l ; ; let let let let plus x y = x+y ; ; addition = fold plus 0 ; ; fois x y = x * y ; ; multiplication = fold fois 1 ; ; Prédéfinie : List.fold_right et List.fold_left 19 / 5