Dans de nombreux langages avec pattern matching, les patterns doivent respecter la restriction de linéarité, qui dit qu'une variable ne peut apparaître qu'une seule fois par pattern. En effet, la sémantique d'une variable dans un pattern est "accepte n'importe quelle entrée et, dans la clause de filtrage, je pourrai utiliser cette variable comme nom sur l'entrée filtrée". Par exemple en caml dans `fun (x, y) -> x + y`, `(x,y)` est un motif qui accepte un couple, et donne le nom "x" au premier composant du couple, et "y" au second. `fun (x,x) -> x` n'a pas de sens (puisqu'il faudrait donner le même nom à deux valeurs différentes) et est rejeté par le compilateur.
Il y a des langages qui autorisent le filtrage non-linéaire, où une variable apparaît plusieurs fois, et dans ce cas la sémantique est "accepte cette clause de filtrage si les différentes valeurs liées par la variable sont égales". Par exemple le pattern `(x, x)` n'accepterait que les couples dont les deux composants sont égaux. Cette approche a en particulier été popularisée par Prolog qui l'utilise comme une des base de la programmation (parce qu'en prolog il n'y a pas vraiment de "motifs" et de "résultat", les variables sont au même niveau et unifiées entre elles). C'est assez naturel, le problème c'est que dans un langage fonctionnel il n'y a pas forcément de notion canonique d'égalité qu'on puisse utiliser (qu'est-ce que ça veut dire, que deux fonctions sont égales ?).
Erlang, comme prolog, utilise une forme de filtrage encore plus étendue : le test d'égalité se fait quand la variable est déjà liée dans le motif courant, mais aussi quand elle est déjà liée dans l'environnement : si tu rencontres la variable X dans un motif, la signification du motif dépend de si la variable X n'existe pas déjà dans le programme (alors elle est fraîche et on la lie), ou de si la variable X est déclarée et que le motif est dans sa portée (alors c'est un test d'égalité).
En pratique cela veut dire que quand tu vois un motif en Erlang, tu ne peux pas connaître sa signification sans lire tout le code "au dessus" pour repérer toutes les déclarations de variable, et savoir si les variables du motif sont déjà dans l'environnement ou non. En particulier, si tu coupes-colle du code d'une fonction à une autre, ton code a des risques de devenir complètement faux pour des raisons subtiles qui sont difficiles à repérer, et dont le compilateur ne pourra pas t'avertir.
Ce comportement (que j'appelle non-linéaire) est utile et expressif. Mais parfois, ce n'est pas le comportement qu'on veut : on veut dire "je ne veux pas savoir si X existe déjà ou non, donne le nom X à cette nouvelle variable et oublie l'ancienne le cas échéant". C'est utile, ça aide le raisonnement local, bref on en a besoin. Et Erlang ne le propose pas (sauf dans le cas de la syntaxe "fun (motif) -> expression end"), ce qui est un défaut. Reia propose deux syntaxes, une pour les filtrages non-linéaires d'Erlang, et une pour les filtrages linéaires (il me semble que c'est "*X". À vérifier).
[^] # Re: Erlang
Posté par gasche . En réponse à la dépêche Apprendre un langage de programmation par an. Évalué à 2.
Il y a des langages qui autorisent le filtrage non-linéaire, où une variable apparaît plusieurs fois, et dans ce cas la sémantique est "accepte cette clause de filtrage si les différentes valeurs liées par la variable sont égales". Par exemple le pattern `(x, x)` n'accepterait que les couples dont les deux composants sont égaux. Cette approche a en particulier été popularisée par Prolog qui l'utilise comme une des base de la programmation (parce qu'en prolog il n'y a pas vraiment de "motifs" et de "résultat", les variables sont au même niveau et unifiées entre elles). C'est assez naturel, le problème c'est que dans un langage fonctionnel il n'y a pas forcément de notion canonique d'égalité qu'on puisse utiliser (qu'est-ce que ça veut dire, que deux fonctions sont égales ?).
Erlang, comme prolog, utilise une forme de filtrage encore plus étendue : le test d'égalité se fait quand la variable est déjà liée dans le motif courant, mais aussi quand elle est déjà liée dans l'environnement : si tu rencontres la variable X dans un motif, la signification du motif dépend de si la variable X n'existe pas déjà dans le programme (alors elle est fraîche et on la lie), ou de si la variable X est déclarée et que le motif est dans sa portée (alors c'est un test d'égalité).
En pratique cela veut dire que quand tu vois un motif en Erlang, tu ne peux pas connaître sa signification sans lire tout le code "au dessus" pour repérer toutes les déclarations de variable, et savoir si les variables du motif sont déjà dans l'environnement ou non. En particulier, si tu coupes-colle du code d'une fonction à une autre, ton code a des risques de devenir complètement faux pour des raisons subtiles qui sont difficiles à repérer, et dont le compilateur ne pourra pas t'avertir.
Ce comportement (que j'appelle non-linéaire) est utile et expressif. Mais parfois, ce n'est pas le comportement qu'on veut : on veut dire "je ne veux pas savoir si X existe déjà ou non, donne le nom X à cette nouvelle variable et oublie l'ancienne le cas échéant". C'est utile, ça aide le raisonnement local, bref on en a besoin. Et Erlang ne le propose pas (sauf dans le cas de la syntaxe "fun (motif) -> expression end"), ce qui est un défaut. Reia propose deux syntaxes, une pour les filtrages non-linéaires d'Erlang, et une pour les filtrages linéaires (il me semble que c'est "*X". À vérifier).