Fonctions du 1er ordre - LRDE
Transcription
Fonctions du 1er ordre - LRDE
Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motifs Approches Fonctionnelles de la Programmation Fonctions du 1er ordre En retour Généralités Motifs Comme objets Didier Verna [email protected] http://www.lrde.epita.fr/˜didier 1/38 Table des matières Programmation Fonctionnelle Didier Verna E PITA Généralités 1 Généralités 2 Fonctions anonymes 3 Arguments fonctionnels Généralités Motifs courants 4 Retours fonctionnels Généralités Motifs Courants 5 Objets fonctionnels Lambda En argument Généralités Motifs En retour Généralités Motifs Comme objets 2/38 Définitions niveau fonction Définitions simples Programmation Fonctionnelle Didier Verna E PITA Lisp Haskell ( defun backwards ( l s t ) ( reverse l s t ) ) backwards : : [ a ] −> [ a ] backwards xs = reverse xs Généralités Lambda En argument Scheme Généralités Motifs En retour ( define ( backwards l s t ) ( reverse l s t ) ) Généralités Motifs Comme objets Lisp Haskell ( s e t f ( symbol−function ’ backwards ) # ’ reverse ) backwards : : [ a ] −> [ a ] backwards = reverse Scheme ( define backwards reverse ) 4/38 Lisp : Symboles Lisp-1 (Scheme) vs. Lisp-2 (Common Lisp) Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motifs En retour Généralités Motifs Comme objets Les symboles contiennent des propriétés, dont une valeur et une valeur fonctionnelle. Un symbole peut dénoter à la fois une variable et une fonction (espaces de noms distincts). defun et defparameter ne sont pas indispensables (macros). 5/38 foobar ..... Valeur Valeur fonctionnelle ( defparameter ∗f o o∗ 3 ) ( defun ∗f o o∗ ( x ) (∗ 2 x ) ) ( s e t f ( symbol−value ’∗ f o o ∗) 3 ) ( s e t f ( symbol−function ’∗ f o o ∗) ( lambda ( x ) (∗ 2 x ) ) ) Lisp : Valeurs vs. valeurs fonctionnelles A PI pour l’appel de fonction Programmation Fonctionnelle Fonction function, read-macro #’ Didier Verna E PITA ( assert ( eq ( f u n c t i o n +) # ’ + ) ) Généralités Lambda Fonction (funcall func &rest args) En argument Généralités Motifs ( f u n c a l l # ’+ 1 2 3 4 5 ) En retour Généralités Motifs Fonction (apply func arg &rest args) Comme objets ( apply # ’+ 1 2 3 ’ ( 4 5 ) ) 6/38 Lisp : Fonctions variadiques De l’influence de la syntaxe. . . Programmation Fonctionnelle Didier Verna E PITA Généralités Un appel de fonction Lisp est syntaxiquement clos : (func arg1 arg2 ...) Fonctions variadiques : Lambda En argument Généralités ( defun m k l i s t ( head &r e s t t a i l ) ( cons head t a i l ) ) ; ; ( mklist ’a ’b ’c) Motifs En retour Généralités Motifs Comme objets ( defun msg ( s t r & o p t i o n a l ( p r e f i x "error: " ) p o s t f i x ) ( concatenate ’ s t r i n g p r e f i x s t r p o s t f i x ) ) ; ; ( msg " h e l l o " n i l " ! " ) ( defun msg∗ ( s t r &key p r e f i x ( p o s t f i x "." ) ) ( concatenate ’ s t r i n g p r e f i x s t r p o s t f i x ) ) ; ; ( msg∗ " h e l l o " : p r e f i x "Me: " ) Plus &-combinaisons . . . 7/38 Haskell : Application partielle et coupure De l’influence de la syntaxe. . . Programmation Fonctionnelle Didier Verna E PITA m u l t i p l y : : F l o a t −> F l o a t −> F l o a t multiply a b = a ∗ b −− m u l t i p l y a b Généralités Lambda En argument Généralités Motifs En retour Généralités Motifs Comme objets -> est associatif à droite Float -> (Float -> Float) L’application est associative à gauche : multiply 2 5 ⇔ (multiply 2) 5 Curryfication : Les fonctions Haskell sont unaires I I 8/38 Application partielle : multiply 2 :: Float -> Float Coupure d’opérateur : (+2) (>3) (3:) ("error: "++) etc. Fonctions anonymes : rappel Des littéraux comme les autres. . . Programmation Fonctionnelle Didier Verna E PITA Généralités Possibilité de ne pas nommer les fonctions : Lisp Haskell ( lambda ( x ) (∗ 2 x ) ) \ x −> 2 ∗ x Lambda Utilisation directe (littérale) : au même titre que les int, les chaînes de caractères etc. En argument Généralités Motifs En retour Généralités Motifs Lisp Haskell ( ( lambda ( x ) (∗ 2 x ) ) 4 ) ( \ x −> 2 ∗ x ) 4 Comme objets 10/38 Contextes locaux et fonctions anonymes Équivalence conceptuelle Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda let ouvre un bloc explicite Les fonctions ouvrent des blocs implicites Grâces aux fonctions anonymes, let est inutile Lisp Lisp ( defun f ( x ) ( l e t ( ( a (∗ x x ) ) ( b (+ (∗ x x ) 1 ) ) ) (+ ( / a b ) ( / b a ) ) ) ) ( defun f ( x ) ( ( lambda ( a b ) (+ ( / a b ) ( / b a ) ) ) (∗ x x ) (+ (∗ x x ) 1 ) ) ) En argument Généralités Motifs En retour Généralités Motifs Comme objets Remarques : I I 11/38 Cela explique pourquoi les références croisées sont impossibles dans un let. Modèle inapplicable à Haskell. Application à let* Imbrication Programmation Fonctionnelle let* se comporte comme des let imbriqués. Didier Verna E PITA Lisp Généralités Lambda En argument Généralités ( defun f ( x ) ( l e t ∗ ( ( a (∗ x x ) ) ( b (+ a 1 ) ) ) (+ ( / a b ) ( / b a ) ) ) ) Motifs En retour Généralités Motifs Comme objets 12/38 Lisp Lisp ( defun f ( x ) ( l e t ( ( a (∗ x x ) ) ) ( l e t ( ( b (+ a 1 ) ) ) (+ ( / a b ) ( / b a ) ) ) ) ) ( defun f ( x ) ( ( lambda ( a ) ( ( lambda ( b ) (+ ( / a b ) ( / b a ) ) ) (+ a 1 ) ) ) (∗ x x ) ) ) Motivation (1) Des formes communes d’abstraction Programmation Fonctionnelle b ∑ f (n) = f (a) + . . . + f (b) Didier Verna E PITA Généralités n=a Lisp Haskell ( defun s i n t ( a b ) ( i f (> a b) 0 (+ a ( s i n t (1+ a ) b ) ) ) ) s i n t : : I n t −> I n t −> I n t sint a b | a > b = 0 | otherwise = a + s i n t ( a +1) b ( defun ssq ( a b ) ( i f (> a b) 0 (+ ( sq a ) ( ssq (1+ a ) b ) ) ) ) ssq : : I n t −> I n t −> I n t ssq a b | a > b = 0 | otherwise = sq a + ssq ( a +1) b ( defun s p i ( a b ) ( i f (> a b) 0 (+ ( / 1 . 0 (∗ a (+ a 2 ) ) ) ( s p i (+ a 4 ) b ) ) ) ) s p i : : I n t −> I n t −> F l o a t spi a b | a > b = 0 | otherwise = 1 . 0 / f r o m I n t e g r a l ( a ∗ a +2) + s p i ( a +4) b Lambda En argument Généralités Motifs En retour Généralités Motifs Comme objets 14/38 Motivation (2) Des formes communes d’abstraction Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Lisp Haskell ( defun sigma ( a b term n e x t ) ( i f (> a b) 0 (+ ( f u n c a l l term a ) ( sigma ( f u n c a l l n e x t a ) b term n e x t ) ) ) ) sigma : : Num a => I n t −> I n t −> ( I n t −> a ) −> ( I n t −> I n t ) −> a sigma a b term next | a > b = 0 | otherwise = term a + sigma ( next a ) b term next ( defun s i n t ( a b ) ( f u n c a l l # ’ sigma a b # ’ identity # ’1+)) s i n t : : I n t −> I n t −> I n t s i n t a b = sigma a b i d ( + 1 ) Généralités Motifs En retour Généralités Motifs Comme objets ( defun ssq ( a b ) ( f u n c a l l # ’ sigma a b # ’ sq # ’ 1 + ) ) ( defun pi−term ( a ) ( / 1 . 0 (∗ a (+ a 2 ) ) ) ) ( defun pi−step ( a ) (+ a 4 ) ) ( defun s p i ( a b ) ( f u n c a l l # ’ sigma a b # ’ pi−term # ’ pi−step ) ) 15/38 ssq : : I n t −> I n t −> I n t ssq a b = sigma sq ( + 1 ) p i t e r m : : I n t −> F l o a t p i t e r m a = 1 . 0 / f r o m I n t e g r a l ( a ∗ a +2) p i s t e p : : I n t −> I n t pistep a = a + 4 s p i : : I n t −> I n t −> F l o a t s p i a b = sigma a b p i t e r m p i s t e p Mapping 1er motif incontournable Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motif : Lisp Haskell ( defun double ( l s t ) ( i f ( null l s t ) nil ( cons (∗ 2 ( c a r l s t ) ) ( double ( c d r l s t ) ) ) ) ) double1 , double2 : : [ I n t ] −> [ I n t ] double1 [ ] = [ ] double1 ( x : xs ) = 2∗x : double1 xs double2 xs = [ 2∗ e l t | e l t <− xs ] Motifs En retour Généralités Motifs Comme objets Lisp : (mapcar func list &rest lists) Haskell : map :: (a -> b) -> [a] -> [b] Exemples : 16/38 Lisp Haskell ( defun double ( l s t ) ( mapcar ( lambda ( x ) (∗ 2 x ) ) lst )) double : : [ I n t ] −> [ I n t ] double = map ( ∗ 2 ) Mapping généralisé Sur plusieurs listes Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motif : Lisp Haskell ( defun l i s t + ( l 1 l 2 ) ( i f ( or ( n u l l l 1 ) ( n u l l l 2 ) ) nil ( cons (+ ( c a r l 1 ) ( c a r l 2 ) ) ( l i s t + ( cdr l 1 ) ( cdr l 2 ) ) ) ) ) ( ! + ) : : [ I n t ] −> [ I n t ] −> [ I n t ] ( ! + ) ( x : xs ) ( y : ys ) = ( x + y ) : xs ! + ys (!+) _ _ = [] Motifs En retour Généralités Motifs Comme objets Lisp : mapcar variadique. Haskell : zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] Exemples : 17/38 Lisp Haskell ( defun l i s t + ( l 1 l 2 ) ( mapcar # ’+ l 1 l 2 ) ) ( ! + ) : : [ I n t ] −> [ I n t ] −> [ I n t ] ( ! + ) = zipWith ( + ) Filtrage / Élimination 2e motif incontournable Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motifs En retour Motif : Lisp Haskell ( defun p s t ( l ) ( cond ( ( n u l l l ) nil ) (( > ( car l ) 0) ( cons ( c a r l ) ( pst ( cdr l ) ) ) ) (t ( pst ( cdr l ) ) ) ) ) pst1 , p s t 2 : : [ I n t ] −> [ I n t ] pst1 [ ] = [ ] p s t 1 ( x : xs ) | x > 0 = x : p s t 1 xs | otherwise = p s t 1 xs p s t 2 xs = [ e | e <− xs , e > 0 ] Généralités Motifs Comme objets 18/38 Lisp : (remove-if[-not] pred list &key ...) Haskell : filter :: (a -> Bool) -> [a] -> [a] Exemples : Lisp Haskell ( defun p s t ( l ) ( remove−if ( lambda ( x ) ( < x 0 ) ) l )) p s t : : [ I n t ] −> [ I n t ] p s t = f i l t e r ( >0) Folding / Réduction 3e motif incontournable Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motifs Motif : Lisp Haskell ( defun l i s t s u m ( l ) ( cond ( ( n u l l l ) ( e r r o r "empty list" ) ) ( ( null ( cdr l ) ) ( car l ) ) ( t (+ ( c a r l ) ( l i s t s u m ( cdr l ) ) ) ) ) ) l i s t s u m : : [ I n t ] −> I n t listsum [ x ] = x l i s t s u m ( x : xs ) = x + l i s t s u m xs En retour Généralités Motifs Comme objets Lisp : (reduce func seq &key ...) Haskell : foldr1 :: (a -> a -> a) -> [a] -> a Exemples : 19/38 Lisp Haskell ( defun l i s t s u m ( l ) ( reduce # ’+ l ) ) l i s t s u m : : [ I n t ] −> I n t listsum = foldr1 (+) Folding généralisé Valeur de retour pour la liste vide Programmation Fonctionnelle Didier Verna E PITA Lisp : clé :initial-value de reduce Remarque : (+) => 0, (*) => 1 Haskell : foldr Généralités Lambda En argument f o l d r : : ( a −> b −> b ) −> b −> [ a ] −> b foldr f s [ ] = s f o l d r f s ( x : xs ) = f x ( f o l d r f s xs ) Généralités Motifs En retour Généralités Motifs Comme objets 20/38 Folding généralisé et récursion primitive : Beaucoup de fonctions primitive-récursives peuvent s’exprimer comme un fold. Lisp Haskell ( defun snoc ( e l t l s t ) ( append l s t ( l i s t e l t ) ) ) snoc : : a −> [ a ] −> [ a ] snoc x xs = xs ++ [ x ] ( defun r e v ( l s t ) ( reduce # ’ snoc l s t : from−end t : initial−value nil )) r e v : : [ a ] −> [ a ] r e v = f o l d r snoc [ ] Recherche / indexation Programmation Fonctionnelle Didier Verna E PITA Recherche : I Généralités Lambda I En argument Généralités Motifs En retour Indexation : I Généralités Motifs Comme objets 21/38 Lisp : (member-if[-not] pred lst &key ...) (réservé aux listes), (find-if[-not] pred seq &key ...) Haskell : find :: (a -> Bool) -> [a] -> Maybe a I Lisp : (position-if[-not] pred seq &key ...) Haskell : findIndex :: (a -> Bool) -> [a] -> Maybe Int Extraction Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motif : Haskell getWord : : S t r i n g −> S t r i n g getWord [ ] = [ ] getWord ( x : xs ) | x == ’ ’ = [ ] | otherwise = x : getWord xs Motifs En retour Généralités Motifs Comme objets Haskell : takeWhile :: (a -> Bool) -> [a] -> [a] dropWhile :: (a -> Bool) -> [a] -> [a] Exemples : Haskell getWord : : S t r i n g −> S t r i n g getWord s t r = dropWhile ( \ x −> x == ’ 22/38 ’) str Divers Comme d’été Programmation Fonctionnelle Didier Verna E PITA Généralités Prédicats : I I Lambda En argument Généralités Motifs Lisp : Fonctions (every|some pred seq &rest seqs) Haskell : Fonctions all|any :: (a -> Bool) -> [a] -> Bool Tri : I En retour Généralités Lisp : Fonction (sort seq pred &key ...) Attention : sort est destructif ! Motifs Comme objets ( setf foo ( sort # ’ > foo ) ) I Haskell : Fonctions sort :: Ord a => [a] -> [a] sortBy :: (a -> a -> Ordering) -> [a] -> [a] 23/38 Motivation Une question d’orthogonalité Programmation Fonctionnelle Fonctions complémentaires de Lisp : Didier Verna E PITA Généralités ( remove−if−not # ’ pred l s t ) ( remove−if ( lambda ( x ) ( not ( pred x ) ) ) ( remove−if ( complement # ’ pred ) l s t ) lst ) Lambda En argument Généralités Motifs I Fonction complement: -50% de prédicats (obsolescence des formes en -not) En retour Généralités Motifs Macro setf : accesseurs en tant que lvalues. . . Comme objets ( defvar f o o ’ ( 1 2 3 4 5 ) ) ( nth 2 f o o ) ; ; => 3 ( s e t f ( nth 2 f o o ) 0 ) ; ; s e t n t h doesn ’ t e x i s t f o o ; ; => ( 1 2 0 4 5 ) 25/38 Lisp : Retours fonctionnels et scoping Problème de la « capture » de variables Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Fonctions constantes : Fonctions à la demande : ( defun +/− ( which_one ) ( i f (= which_one 0 ) # ’+ # ’−)) ( defun make−adder ( n ) # ’ ( lambda ( x ) (+ x n ) ) ) ; ; ( f u n c a l l ( make−adder 3 ) 1 ) ; ; ( f u n c a l l (+/− 0 ) 4 2 ) Généralités Motifs En retour Généralités Motifs Comme objets Scoping dynamique : retour fonctionnel limité aux fonctions constantes Scoping lexical : retour de fonctions créés à la demande en toute sécurité ( defun complement ( f n ) # ’ ( lambda (& r e s t args ) ( not ( apply f n args ) ) ) ) Remarque : retour fonctionnel et fermetures lexicales = coût principal d’implémentation du 1er ordre. 26/38 Haskell : Rappels Retours fonctionnels cachés Programmation Fonctionnelle Didier Verna E PITA Généralités Coupure d’opérateur / application partielle : (+3) :: Int -> Int Définition niveau fonction : Lambda En argument Généralités Motifs En retour Généralités Motifs Comme objets 27/38 adder : : I n t −> ( I n t −> I n t ) adder n = \ x −> x + n adder : : I n t −> ( I n t −> I n t ) adder n = add where add x = x + n −− ( adder 3 ) 1 −− ( adder 3 ) 1 Composition de fonctions Programmation Fonctionnelle Didier Verna E PITA Lisp Haskell ( defun i s o d d ( n ) ( not ( evenp n ) ) ) i s o d d : : I n t e g e r −> Bool i s o d d n = not ( even n ) ( defun compose (& r e s t f n s ) ; ; Not t r i v i a l . Only t h e f i r s t ; ; f u n c t i o n can be v a r i a d i c . ) i s o d d : : I n t e g e r −> Bool i s o d d = not . even Généralités Lambda En argument Généralités Motifs En retour Généralités Motifs ( defun i s o d d ( n ) ( compose # ’ not # ’ evenp ) ) Comme objets complement : cas particulier de compose Type Haskell : (.) :: (b -> c) -> (a -> b) -> (a -> c) Associativité de . : f . (g . h) = (f . g) . h = f . g .h Précédence Haskell : f . g x = f . (g x) 28/38 Composition itérative f n (x) Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Vision récursive : Lisp Haskell ( defun i t e r ( n f ) ( i f ( > n 0) ( compose f ( i t e r (1− n ) f ) ) # ’ identity )) i t e r : : I n t −> ( a −> a ) −> ( a −> a ) iter n f | n > 0 = f . i t e r ( n − 1) f | otherwise = i d Généralités Motifs Vision fold’esque : En retour Généralités Motifs Comme objets ( defun i t e r ( n f ) ( reduce # ’ compose ( make−list n : i n i t i a l − e l e m e n t f ) : initial−value # ’ identity : from−end t ) ) i t e r : : I n t −> ( a −> a ) −> ( a −> a ) i t e r n f = foldr ( . ) id ( replicate n f ) 29/38 (Dé) Curryfication Arité des fonctions Programmation Fonctionnelle Didier Verna E PITA Généralités Formes (dé) curryfiée : Haskell Haskell m u l t i p l y : : I n t −> I n t −> I n t multiply a b = a ∗ b m u l t i p l y : : ( I n t , I n t ) −> I n t multiply (a, b) = a ∗ b Lambda En argument Généralités Haskell : (Dé) Curryfication Motifs En retour Généralités Motifs Comme objets 30/38 curry : : ( ( a , b ) −> c ) −> ( a −> b −> c ) curry g x y = g ( x , y ) uncurry : : ( a −> b −> c ) −> ( ( a , b ) −> c ) uncurry g ( x , y ) = g x y Lisp : Currification partielle Lisp Lisp ( defun c u r r y ( f n &r e s t args ) # ’ ( lambda (& r e s t args2 ) ( apply f n ( append args args2 ) ) ) ) ( defun r c u r r y ( f n &r e s t args ) # ’ ( lambda (& r e s t args2 ) ( apply f n ( append args2 args ) ) ) ) Récurseurs de listes Version initiale Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motif : ( defun l e n ( l s t ) ( i f ( null l s t ) 0 (1+ ( l e n ( c d r l s t ) ) ) ) ) l e n : : [ a ] −> I n t len [ ] = 0 l e n ( x : xs ) = 1 + l e n xs Récurseur : Motifs En retour Généralités Motifs Comme objets ( defun l r e c ( f n v a l ) ( labels ( ( s e l f ( l s t ) ( i f ( null l s t ) val ( funcall fn ( s e l f ( cdr l s t ) ) ) ) ) ) #’ self )) ; ; ( f u n c a l l ( l r e c # ’1+ 0 ) ’ ( 1 2 3 4 5 ) ) => 5 l r e c : : ( a −> a ) −> a −> ( [ b ] −> a ) lrec fn val = le t s e l f [ ] = val s e l f ( x : xs ) = f n ( s e l f xs ) in s e l f −− ( l r e c ( 1 + ) 0 ) [ 1 , 2 , 3 , 4 , 5 ] => 5 31/38 Récurseurs de listes Version générale Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motifs Motif : ( defun every1 ( p l s t ) ( i f ( null l s t ) t ( and ( f u n c a l l p ( c a r l s t ) ) ( every1 p ( cdr l s t ) ) ) ) ) a l l 1 : : ( a −> Bool ) −> [ a ] −> Bool a l l 1 _ [ ] = True a l l 1 p ( x : xs ) = p x && a l l 1 p xs Récurseur : En retour Généralités Motifs Comme objets 32/38 ( defun l r e c 1 ( f n v a l ) ( labels ( ( s e l f ( l s t ) ( i f ( null l s t ) val ( funcall fn ( car l s t ) # ’ ( lambda ( ) ( s e l f ( cdr l s t ) ) ) ) ) ) ) #’ self )) l r e c 1 : : ( a −> b −> b ) −> b −> ( [ a ] −> b ) lrec1 fn val = let s e l f [ ] = val s e l f ( x : xs ) = f n x ( s e l f xs ) in s e l f Application Récurseurs communs Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motifs En retour Généralités ; ; every f o r some PREDicate ( l r e c 1 # ’ ( lambda ( e l t c n t ) ( and (PRED e l t ) ( f u n c a l l c n t ) ) ) t ) ; ; some f o r some PREDicate ( l r e c 1 # ’ ( lambda ( e l t c n t ) ( or (PRED e l t ) ( f u n c a l l c n t ) ) ) nil ) ; ; f i n d − i f f o r some PREDicate ( l r e c 1 # ’ ( lambda ( e l t c n t ) ( i f (PRED e l t ) e l t ( f u n c a l l c n t ) ) ) ; ; remove−if−not f o r some PREDicate ( l r e c 1 # ’ ( lambda ( e l t c n t ) ( i f (PRED e l t ) ( cons e l t ( f u n c a l l c n t ) ) ( funcall cnt ) ) ) n i l ) Motifs Comme objets −− a l l f o r some PREDicate l r e c 1 ( \ e l t c n t −> PRED e l t && c n t ) True −− any f o r some PREDicate l r e c 1 ( \ e l t c n t −> PRED e l t | | c n t ) False −− f i n d f o r some PREDicate l r e c 1 ( \ e l t c n t −> i f PRED e l t then Just e l t else c n t ) Nothing −− f i l t e r f o r some PREDicate l r e c 1 ( \ e l t c n t −> i f PRED e l t then ( e l t : c n t ) else c n t ) [ ] 33/38 nil ) Lisp : Récurseurs d’arbres Représentation par liste hétérogène Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Motifs : ( defun l e a v e s ( t r e e ) ( i f ( atom t r e e ) 1 (+ ( l e a v e s ( c a r t r e e ) ) ( or ( i f ( c d r t r e e ) ( l e a v e s ( c d r t r e e ) ) ) 1)))) Généralités Motifs En retour Généralités Motifs Comme objets 34/38 ( defun f l a t t e n ( t r e e ) ( i f ( atom t r e e ) ( l i s t tree ) ( append ( f l a t t e n ( c a r t r e e ) ) ( i f ( cdr t r e e ) ( f l a t t e n ( cdr t r e e ) ) ) ) ) ) Application leaves et flatten Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motifs En retour Généralités Récurseur : ( defun t r e c ( f n v a l ) ( labels ( ( s e l f ( tree ) ( i f ( atom t r e e ) ( funcall val tree ) ( funcall fn # ’ ( lambda ( ) ( s e l f ( car t r e e ) ) ) # ’ ( lambda ( ) ( i f ( cdr t r e e ) ( s e l f ( cdr t r e e ) ) ) ) ) ) ) ) #’ self )) Motifs Comme objets Exemples : ; ; leaves ( t r e c # ’ ( lambda ( l c n t r c n t ) (+ ( f u n c a l l l c n t ) ( or ( f u n c a l l r c n t ) 1 ) ) ) # ’ ( lambda ( e l t ) 1)) 35/38 ; ; flatten ( t r e c # ’ ( lambda ( l c n t r c n t ) ( append ( f u n c a l l l c n t ) ( f u n c a l l r c n t ) ) ) #’ list ) Qu’appelle t’on « donnée » ? Programmation Fonctionnelle Didier Verna E PITA En général : I I Généralités Lambda En argument Généralités Motifs En retour Généralités Motifs Comme objets 37/38 Représentation : structures de données Manipulation : fonctions sur les données Abstraction de données / interface : I I I Constructeurs, accesseurs et manipulateurs Conditions d’ inter-fonctionnement Toute implémentation doit satisfaire ces conditions Conclusion : I I Distinguer l’interface de son implémentation Toute implémentation peut convenir, y compris une implémentation fonctionnelle (fermetures lexicales) au lieu de structures de données Lisp : Listes fonctionnelles Application Programmation Fonctionnelle Didier Verna E PITA Généralités Lambda En argument Généralités Motifs En retour Généralités ( defun f c o n s ( c a r c d r ) ( l a b e l s ( ( d i s p a t c h ( arg ) ( cond ( ( = 0 arg ) car ) (t cdr ) ) ) ) # ’ dispatch ) ) ( defun f c a r ( o b j ) ( funcall obj 0)) ( defun f c d r ( o b j ) ( funcall obj 1)) Motifs Comme objets Les fonctions du 1er ordre (fermetures lexicales) permettent la représentation de données complexes. L’implémentation fonctionnelle utilise une stratégie d’« envoi de message » (message passing). 38/38