Image loader
Image loader

Le λ-calcul en programmation : Part.1 Introduction et syntaxe

16/11/2022
programmation | théorie
link logo
Post thumbnail

Introduction

Mais qu'est-ce donc, le λ\lambda-calcul ?

Le λ\lambda-calcul est un langage de programmation théorique, à la base de tous les langages de programmation fonctionnels que vous pouvez connaître. Je pense notamment à Lisp, Scheme, OCaml, Haskell... et bien d'autres ! Les concepts du λ\lambda-calcul sont même appliqués à la plupart des langages orientés objet ou impératifs que nous connaissons tous. Aujourd'hui, les λ\lambda-expressions sont implémentées (plus ou moins bien, j'en conviens) en C++, en Java; en Javascript, et même avec Python. Surtout, n'allez pas dire que ces langages sont fonctionnels, certains puristes vous feraient pendre pour de tels propos.

Petit point histoire, le λ\lambda-calcul a été inventé par Alonzo Church, mathématicien et logicien américain a qui l'on doit (presque) tout en matière d'informatique aujourd'hui. Cette invention remonte environ à 1930, donc bien avant que nous commencions à faire mumuse avec les premiers ordinateurs.

Nous allons tenter ensemble de vulgariser les concepts de base du λ\lambda-calcul, afin d'avoir au moins une petite idée de son utilité et de son importance dans toutes les avancées en matière de programmation. Qui dit vulgarisation dit simplification, et même approximation. Si un logicien puriste passe par là, merci d'en tenir compte avant de me lyncher. Par ailleurs, n'hésitez à me contacter si vous souhaitez discuter d'un point particulier ou me faire part d'une erreur rédhibitoire de ma part.

Syntaxe des λ\lambda-termes

Avant de définir de manière rigoureuse ce qu'est un λ\lambda-terme, observons directement à quoi ressemble une expression simple :

xx

Hein, mais qu'elle est cette diablerie ?

Oui, le symbole xx, tout seul, est une expression valide dans le λ\lambda-calcul. On peut voir cela comme une expression atomique, une sorte de boîte noire. Laissons cette expression de côté et passons à la suivante :

λx.x\lambda x.x

Décortiquons ensemble cette expression :

  • Le symbole λ\lambda signifie que nous définissons une fonction. Afin de faire l'analogie avec ce qui est connu, c'est l'équivalent du mot-clé function en JavaScript.

  • Le xx entre le symbole λ\lambda et le "." est le nom du paramètre de notre fonction.

  • Certains aiment voir ce "." comme la flèche -> ou => de la notation de fonction fléchée avec OCaml ou Javascript. On peut voir aussi le "." comme le mot-clé return dans une fonction.

  • Ce qu'il y a après le ".", ici un autre symbole xx, c'est le résultat de notre fonction, ce qu'elle nous renvoie.

Ainsi, si nous utilisons le JavaScript afin de "traduire" cette λ\lambda-expression, on obtient :

Avec la notation fléchée, très pratique pour représenter les λ\lambda-termes

1(x) => x;

Avec la notation classique :

1function(x) { 2 return x 3}

Étant donné la forte proximité de la syntaxe des fonctions fléchées en JavaScript avec celle du λ\lambda-calcul, on utilisera celle-ci à partir de maintenant, lorsqu'on essaiera de traduire une λ\lambda-expression en code.

Donc, très simplement, on s'aperçoit que la λ\lambda-expression λx.x\lambda x.x représente la fonction identité, qui, à un paramètre xx, associe xx, lui-même. Plutôt simple, non ?

Bien, passons à une autre expression :

x  yx \; y

Ici, le terme xx suivi du terme yy intuite une application de fonction. Plus exactement, c'est l'application d'une fonction xx, avec yy passé en paramètre. Pour y voir un peu plus clair, on écrirait en JavaScript :

1x(y);

Maintenant, afin de mélanger un peu toutes les λ\lambda-expressions précédentes, essayons de déduire le sens de celle-ci (sans regarder la réponse plus bas bien entendu 😉) :

λx.λy.xy\lambda x. \lambda y . xy

Si nous traduisons cette expression en code, de manière analogue à précédemment, on obtient :

1(x) => (y) => x(y);

En français, on dirait :

"Une fonction qui prend en paramètre un argument x et qui renvoie une fonction qui prend en paramètre un argument y et qui renvoie x appliqué à y".

Pensez à réciter ce que sont les λ\lambda-expressions en langage naturel, c'est un moyen de comprendre rapidement une expression.

Maintenant, je pense que vous êtes fin prêts à gober la définition (inductive) exacte de l'ensemble des λ\lambda-termes qui est :

L'ensemble des λ\lambda-termes du λ\lambda-calcul est le plus petit ensemble qui contient :

  1. xx si xx appartient à un ensemble donné de variables. De manière formelle, on écrit xx si xVarx \in Var

  2. λx.M\lambda x.M si MM est une λ\lambda-expression et xx est une variable

  3. (MN)(MN) si MM et NN sont tous les deux des λ\lambda-expressions

C'est tout. Ces trois règles de construction, à elles seules, définissent toutes les λ\lambda-expressions qu'il est possible d'écrire dans le λ\lambda-calcul, tel qu'il a été initialement défini.

Allez, une petite dernière pour la route, plus compliquée cette fois, manière de voir si on a attrapé le truc :

(λx.λy.xy)  (λx.x)  z(\lambda x . \lambda y . xy) \; (\lambda x . x) \; z

Alors, tout d'abord, nous pouvons nous demander : "Est-ce une expression valide dans le λ\lambda-calcul " ? Voyons-si la syntaxe est valide :

Tout d'abord, si on pose :

M=(λx.λy.xy)N=(λx.x)  zM = (\lambda x . \lambda y . x y) \\ N = (\lambda x . x) \; z

Alors, on a notre règle 3 définie plus haut qui est respectée pour l'instant ☑️. Maintenant, la sous-expression M=(λx.λy.xy)M =(\lambda x . \lambda y . x y) est-elle valide ?

Si on pose :

O=x  yO = x\;y

Alors, on a M=λy.O M = \lambda y . O, et on reconnait une cette fois notre règle 2 ☑️. Au passage, on reconnait une expression déjà vue plus haut. Il reste à vérifier que la sous- expression OO est aussi valide. Si nous posons :

P=xQ=yP = x \\ Q = y

Alors on reconnait une application de fonction avec la règle 3, et, de même, on constate que PP et QQ sont également des expressions valides à l'aide de la règle 1 ☑️.

Bon, on en a fini avec MM. Voyons maintenant si N=(λx.x)  zN = (\lambda x . x) \; z est une expression valide :

On commence à avoir l'habitude, si on pose :

R=λx.xS=zR = \lambda x . x \\ S = z

En utilisant la règle 3 on reconnait encore une application de fonction ☑️. Au passage, on s'aperçoit rapidement que la sous-expression SS vérifie la règle 1 ☑️. Il ne nous reste plus qu'à vérifier si R=λx.xR = \lambda x . x est une expression valide, ce qui est le cas, car nous reconnaissons la fonction identité vue auparavant, la règle 2 est satisfaite, et toute notre expression est donc valide ☑️. s Ouf! 😅 . Rassurez-vous, inutile de décortiquer chaque expression de la sorte. Ici, nous le faisons une fois pour être sûr de la compréhension des règles, mais ça vient assez rapidement de constater, en un coup d'œil, s'il y a un problème de syntaxe dans une λ\lambda-expression.

Maintenant, la traduction en Javascript :

1((x) => (y) => x(y))((x) => x)(y);

Oui, je vous assure que ce code javascript est complètement valide ! Même si peu lisible, c'est vrai.

Au passage, on remarque que les règles de construction du λ\lambda-calcul font que nos fonctions ne peuvent prendre qu'un seul argument et sont contraintes de renvoyer une valeur. Nous verrons dans le prochain chapitre que, par la curryfication, ça n'est pas du tout un problème. Pour ceux d'entre vous qui êtes déjà familiers avec les concepts de programmation fonctionnelle, ce comportement est une base des langages fonctionnels dits purs.

C'est tout pour ce premier chapitre !

"Mais attends, on n'a rien calculé du tout là ?" . En effet, le concept du λ\lambda-calcul demandant un certain niveau d'abstraction, je préfère prendre le temps et donc, ce premier article est consacré à l'apprentissage de la syntaxe seule du λ\lambda-calcul, et de l'intuition qu'il y a derrière en matière de sémantique.

Cependant, peut-être avez-vous remarqué que la dernière expression que nous avons vue est "calculable", alors vous pouvez toujours essayer de la réduire, si vous avez une intuition de la manière de faire ! N'hésitez pas à me contacter si vous souhaitez discuter du résultat.

Le prochain chapitre sera consacré au calcul des λ\lambda-expressions, processus que l'on appelle une βreduction\beta-reduction dans le jargon.

À bientôt !

contact email
LinkedIn page link
Facebook page link
Malt page link

Copyright @2024 All rights reserved

With help ofCerbulean Ana-Maria