Ton argumentation me rend perplexe. J'ai l'impression que tu dis qu'Erlang n'est pas un langage fonctionnel, puisqu'il ne permet pas de créer des fonctions locales, et que la syntaxe "fun" est juste du sucre syntaxique proche d'une fonction pour autre chose de moins expressif (moins expressif puisqu'on n'envisage pas d'y ajouter la récursion).
Non, je dis que fun est une sauvegarde d'état, qui ne doit en aucun cas être prise pour une fonction locale. Après comme on est dans un langage fonctionelle fort (i.e pas de porte de sortie pour faire un peu de procédural ici ou là) toutes les fonctions peuvent être considérée comme locale.
En même temps, ton discours "tu peux l'utiliser où tu veux dans ton code, le passer en paramètre ..." est exactement celui que l'on utilise pour décrire des fonctions de première classe. Des fonctions quoi.
Non un état ets en quelque sorte l'inverse d'une fonction
Si on a F : x-> pleins_de_trucs.
alors F est la fonction et x est l'état.
Sauf que contrairement à un matching standard ton etat peut posséder de la logique propre à lui (mais toujours totalement dissociée de la logique de F)
mais peut-être que si la syntaxe était mieux pensée sur ce point, les gens pourraient s'en servir de temps en temps.
La logique Erlang va vraiement à l'encontre de fonctions locales telles que tu les souhaites. Chaque morceau doit être patchable à chaud, distribuable etc. Dans cet optiques de nombreux choix ont été faits, un de ces choix est de dire que les variables ne sont pas modifiables et que les scopes sont tous locaux à la fonction qui s'execute. Vouloir faire de la récursion en local au sein d'une fonction n'est donc pas très utile...
Un exemple serait plus parlant. Imagine que j'ai une fonction Erlang un peu grosse, qui définit une fonction locale (parce que cette fonction utilise des variables définies plus haut dans le bloc, et qu'elle n'a de sens que dans ce contexte donc polluerait inutilement le niveau global).
Déjà je t'arrête, il n'y a pas de niveau global à polluer. Fais ta fonction/ton module tranquillement. Autre particularité d'Erlang, il y a 99 chances sur 100 qu'il gère mieux la concurence que toi. Il faut donc faire autant de fonctions que possible sans que ca gène trop la lisibilité.
Mais je ne peux pas, car `F` n'est pas définie dans le corps de la fonction.
Non, tu ne peux pas parceque F n'est pas une fonction locale au sens langage C du terme, mais un etat. F(N-1) ne veut rien dire, puisque F(N) a déjà été appelé et que l'état a déjà été assigné. C'est pour çà que le compilo te jette. De façon générale tu n'as aucun moyen de faire appel à la logique à l'intérieur de F, vu que cette logique n'a pas de nom par laquelle l'appeler (c'est le truc des fonctions locales d'ailleurs). Fondamentalement vu que tu ne peux pas l'appeler, tu vas avoir du mal à faire de la récursion dessus.
J'aimerais avoir une syntaxe pour faire ça, par exemple :
La méthode la plus simple est d'utiliser le keyword apply sur une fonction d'un module extérieur.
D'abord un module avec al fonction factorielle dedans :
-module(m).
-export([fact/1]).
fact(N) when N>0 ->
N * fact(N-1);
fact(0) ->
1.
Ensuite on applique gentillement dans la fonction
mafonction (X,Y,Z) ->
...
Mafact = apply (m,fact,A)
....
On a 0 passage d'arguments en dehors de la fonction.
A noter que c'est un très mauvais exemple, Dans le cas ou l'on connait à l'avance le nombre d'arguments (et pour la factorielle il y a pas photo), il est TOUJOURS préférable de faire appel à la fonction du module directement.
donc pour écrire le code :
mafonction (X,Y,Z) ->
...
Mafact = m:fact(A)
....
De façon générale fun et apply sont utilisés dans des cas très particuliers, à savoir quand on ne sait pas à l'étape de compilation ce qui va se passer ou quand on est obligé de bloquer une ressource, de faire un commit ou de chercher une cohérence par rapport à un élément extérieur au langage lui même.
[^] # Re: Erlang
Posté par Jerome Herman . En réponse à la dépêche Apprendre un langage de programmation par an. Évalué à 3.
Non, je dis que fun est une sauvegarde d'état, qui ne doit en aucun cas être prise pour une fonction locale. Après comme on est dans un langage fonctionelle fort (i.e pas de porte de sortie pour faire un peu de procédural ici ou là) toutes les fonctions peuvent être considérée comme locale.
En même temps, ton discours "tu peux l'utiliser où tu veux dans ton code, le passer en paramètre ..." est exactement celui que l'on utilise pour décrire des fonctions de première classe. Des fonctions quoi.
Non un état ets en quelque sorte l'inverse d'une fonction
Si on a F : x-> pleins_de_trucs.
alors F est la fonction et x est l'état.
Sauf que contrairement à un matching standard ton etat peut posséder de la logique propre à lui (mais toujours totalement dissociée de la logique de F)
mais peut-être que si la syntaxe était mieux pensée sur ce point, les gens pourraient s'en servir de temps en temps.
La logique Erlang va vraiement à l'encontre de fonctions locales telles que tu les souhaites. Chaque morceau doit être patchable à chaud, distribuable etc. Dans cet optiques de nombreux choix ont été faits, un de ces choix est de dire que les variables ne sont pas modifiables et que les scopes sont tous locaux à la fonction qui s'execute. Vouloir faire de la récursion en local au sein d'une fonction n'est donc pas très utile...
Un exemple serait plus parlant. Imagine que j'ai une fonction Erlang un peu grosse, qui définit une fonction locale (parce que cette fonction utilise des variables définies plus haut dans le bloc, et qu'elle n'a de sens que dans ce contexte donc polluerait inutilement le niveau global).
Déjà je t'arrête, il n'y a pas de niveau global à polluer. Fais ta fonction/ton module tranquillement. Autre particularité d'Erlang, il y a 99 chances sur 100 qu'il gère mieux la concurence que toi. Il faut donc faire autant de fonctions que possible sans que ca gène trop la lisibilité.
Mais je ne peux pas, car `F` n'est pas définie dans le corps de la fonction.
Non, tu ne peux pas parceque F n'est pas une fonction locale au sens langage C du terme, mais un etat. F(N-1) ne veut rien dire, puisque F(N) a déjà été appelé et que l'état a déjà été assigné. C'est pour çà que le compilo te jette. De façon générale tu n'as aucun moyen de faire appel à la logique à l'intérieur de F, vu que cette logique n'a pas de nom par laquelle l'appeler (c'est le truc des fonctions locales d'ailleurs). Fondamentalement vu que tu ne peux pas l'appeler, tu vas avoir du mal à faire de la récursion dessus.
J'aimerais avoir une syntaxe pour faire ça, par exemple :
La méthode la plus simple est d'utiliser le keyword apply sur une fonction d'un module extérieur.
D'abord un module avec al fonction factorielle dedans :
-module(m).
-export([fact/1]).
fact(N) when N>0 ->
N * fact(N-1);
fact(0) ->
1.
Ensuite on applique gentillement dans la fonction
mafonction (X,Y,Z) ->
...
Mafact = apply (m,fact,A)
....
On a 0 passage d'arguments en dehors de la fonction.
A noter que c'est un très mauvais exemple, Dans le cas ou l'on connait à l'avance le nombre d'arguments (et pour la factorielle il y a pas photo), il est TOUJOURS préférable de faire appel à la fonction du module directement.
donc pour écrire le code :
mafonction (X,Y,Z) ->
...
Mafact = m:fact(A)
....
De façon générale fun et apply sont utilisés dans des cas très particuliers, à savoir quand on ne sait pas à l'étape de compilation ce qui va se passer ou quand on est obligé de bloquer une ressource, de faire un commit ou de chercher une cohérence par rapport à un élément extérieur au langage lui même.