Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 typedef struct { int arg; int(*f)(int a, int b); } partial; int add(int a, int b) { return a + b; } partial addN(int a) { partial p = { a, add }; return p; } int apply(partial p, int b) { return p.f(p.arg, b); } int main() { partial add3 = addN(3); return apply(add3, 4); }
Ben oui on est d'accord. On peut tout faire en C ou assembleur (encore heureux) mais cela ne fait pas partie du langage de base. car sinon dans ce cas tous les langages deviennent fonctionnel (sauf java ).
Par exemple dans ton cas, tu ne peux pas utiliser tes fonctions comme des fonctions standards du C (c'est à dire un pointeur de fonction). En gros tu viens de montrer pourquoi le C n'est pas un langage fonctionnel. Qu'on puisse l'émuler, c'est l'évidence, on peut faire ce que tu as fait dans n'importe quel langage Turing puissant.
Je vous le dis à la fin on va tous tomber d'accord sur ce qu'est un langage fonctionnel (on est pas d'accord sur la définition mais on est toujours d'accord sur la liste des langages qui le sont, je vous jure j'ai eu cette discussion je ne sais combien de fois).
Pareil en Lisp :On peut tout faire en C ou assembleur (encore heureux) mais cela ne fait pas partie du langage de base
Ça ne marche pas, de base. Mais on peut contourner la limitation.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 (defun f (a b) (+ a b)) (f 3)
Ce que je ne comprends pas, c'est pourquoi tu persistes à accorder tant d'importance à l'application partielle. Utiliser comme critère "avoir des fonctions de première classe" (merci Ubiquité de m'avoir repris) porte beaucoup moins à discussion, je crois.
non mais ça oui
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 (defun f (a b) (+ a b)) (defun fpart3 (a) (f 3 a))
Le C ne considère pas que les fonctions sont des citoyens de première classe , pourtant il m'a toujours donné cette impression ? Pourquoi je m'acharne, car quand vous allez répondre à cette question (là sur le C) vous allez me dire << non car je peux pas écrire ça >> et là je vais répondre, << tiens tu parles exactement de l'application partielle >>. J'essaye pas de vous convaincre que ma définition est la bonne, j'essaye juste de vous montrer que l'on a tous la même mais que personne ne s'exprime bien (spécialement moi, je sais).
Non mais à partir du moment où tu as des fermetures (c'est à dire des fonctions locales capturant leur environnement) tu as l'application partielle, au pire par eta expansion (ce que tu viens de faire en lisp), mais plus simplement par définition de fonction retournant une fonction. C'est juste un effet secondaire du reste. Ce qui est important c'est la capture
Pour reprendre encore une fois l'exemple classique, quand en caml, tu écris
C'est comme si tu écrivais
Code : Sélectionner tout - Visualiser dans une fenêtre à part let add x y = x +y
(j'ai rajouté un let pour souligner mon point). C'est à dire une fonction qui retourne une fonction ayant *capturé* l'argument de la première fonction. Donc capture => application partielle. Donc application partielle est moins importante !
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 let add x1 = let x = x1 in fun y -> x +y
On y arrive, ce que tu appelles capture, j’appelle ça application partielle. Par contre je ne sais pas ce que tu appelles application partielle.
Le problème vient du fait qu'il n'y a pas de définition précise de ce qu'est une application partielle. Et pour avoir aborder ce sujet la seule définition précise que l'on m'a un jour sortie ne s'appliquait à aucun langage existant.
A quoi fais-tu allusion ? Je ne me souviens pas avoir prétendu quoique ce soit sur les capacités (ou incapacités) de l'assembleur.
Définis alors ce que tu entends ici par "supporte l'application partielle".
Définis "facilement" et "créer une fonction qui ajoute 3 à partir d'une fonction qui additionne deux entiers". Parce que je vois de moins en moins comment tu cherches à définir ça.
La capture de l'environnement ne se limite pas à pouvoir faire de "l'application partielle".
C'est une blague ?
Parce que ça c'est équivalent en C à :
La grosse différence dans cette exemple, c'est le typage dynamique/statique pas fonctionnel/non fonctionnel.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 int f(int a, int b) { return a+b; } int fpart3(int a) { return f(3, a); }
Je ne veux pas dire par là que Lisp n'est pas fonctionnel (ni que le C l'est) ni que les fermetures, les fonctions d'ordre supérieur ou autre chose n'existe pas. Seulement que l'exemple ne montre rien de ceci.
Ce qui se rapprocherait le plus de ce que tu cherches à faire est probablement quelque chose du style de (n'ayant pas fait de Lisp depuis très très longtemps, je ne suis pas 100% certain de la syntaxe) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 (defun f(a) (lambda (b) (+ a b)))
Oui car là l'argument vient d'une constante, mais si je fais ce qui suit, que fais-tu en C (je le fais en caml syntaxe, car je ne suis pas sur du lisp).
Bon ok cette fonction est nulle et inintéressante mais elle fait de l'application partielle cette fonction et je te vois mal la coder en C.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 let partial_apply (f : 'a -> 'b -> 'c) (x : 'a) = f x
Mais où diable as-tu vu que je prétendais pouvoir faire ce genre de chose en C ?
Je ne faisait que remarquer que ton exemple en Lisp, dont le but était visiblement de réfuter la remarque de LLB, ne correspondait en rien à la problèmatique en cours et surtout pas à de "l'application partielle" (ou a quelques autres particularités des langages fonctionnels que ce soit).
Je vais faire du multiréponse.
Non je parlais du fait que le C est une micro couche au dessus de l'assembleur et rien d'autres. Tu m'a dit que non et aujourd'hui je demande encore à voir. J'ai vu des milliers de gens hurler quand je dis que le C est une petite couche au-dessus de l'assembleur, mais j'en ai vu aucun me montrer du C qui ne se traduisait pas à la volée sans réflexion en assembleur, et ce, trivialement en ne faisant pas plus que ce que fait le programme C. Rien à voir avec ce que je devrais faire pour traduire un langage fonctionnel.
Ton pointeur vers du code, moi j'appelle ça un pointeur de fonction. Et d'ailleurs un pointeur de fonction en C est directement traduit par l'objet que tu décris. Si tu veux pas appeler ça un pointeur de fonction c'est ton droit. Mais c'est le mien de l'appeler ainsi. Et on remarquera qu'à l'inverse caml doit créer une structure pour les closure car justement ce que caml veut c'est compliqué pour de l'asm.Envoyé par bluestorm
Quand j'ai fait de l'assembleur (j'avais déjà fait du C) je me suis rendu compte que c'était exactement la même chose que le C avec la gestion des registres en plus. Les programmes sont structurés pareil. Le C a été directement pensé depuis l'assembleur pour être une micro couche et cacher les registres (rendre l'assembleur portable). C'est pour ça que toutes ce que le C sait faire vient de l'assembleur. Avant de dire non, écris moi un exemple de code C qui soit vraiment autre chose que ce que l'assembleur sait faire.
P.S : J'en ai marre de ce dialogue de sourds ou chacun parle sans comprendre l'autre. Ça ne mène franchement à rien. Mais je répondrai jusqu'au bout malheureusement, j'en suis désolé, je ne peux pas laisser qqn dire que je me trompe quand ce n'est pas le cas. Désolé.
Si on parle d'un assembleur du 21eme siecle, c'est à dire RISC comme par exemple l'ia-64, je te garantie qu'un programmeur C avec un compilateur basic fera mieux que toi, n'importe comment.
De plus, ca serai pas mal que t'acquiére un minimum un terminologie correcte avant de vouloir débattre, histoire que le reste du monde comprenne ce que tu écris.
Ouh ca vole haut, je tremble ~~~~ (stupeur et tremblement). Ma terminologie est correcte. Dis moi quel mot j'ai mal employé. Donne moi alors une définition précise et ensuite on en discute. Car lancer des accusations comme ça, sans aucune argumentation, c'est petit et ridicule.
Après oui je vois bien que les gens ne comprennent pas ce que je dis.
Je parlais de l'asm du 386, pas d'un autre assembleur (je ne pensais pas que c'était nécessaire de le préciser).
L'assembleur a un système de typage comme le C, un mot-clé const, des conversions implicites, une bibliothèque standard, une fonction printf, un mot-clé static... ? Non, le C se résume pas uniquement à l'allocation des registres et à des push-pop.C'est pour ça que toutes ce que le C sait faire vient de l'assembleur. Avant de dire non, écris moi un exemple de code C qui soit vraiment autre chose que ce que l'assembleur sait faire.
Si tu veux dire que le C peut être traduit en assembleur, ok, on le savait. Si tu veux dire que le C est plus bas-niveau, plus proche de l'assembleur, que la plupart des langages, ok, on le savait.
Si tu considères que f est une fonction qui prend deux arguments, alors l'équivalent direct en C et en Lisp échouera. Une fonction à deux arguments ne peut pas être appelée avec un seul. Tu pourras dire que l'on peut contourner la limitation en Lisp, mais on peut aussi le faire en C (c'est un peu plus long parce qu'il n'a pas autant de mécanismes d'abstraction que Lisp). La différence profonde que tu essaies de montrer avec tes exemples, c'est ce que l'on a dit depuis le début : les fonctions de Lisp sont des objets de première classe.que fais-tu en C (je le fais en caml syntaxe, car je ne suis pas sur du lisp).
Code : Sélectionner tout - Visualiser dans une fenêtre à part let partial_apply (f : 'a -> 'b -> 'c) (x : 'a) = f x
Si tu considères que f est une fonction à un argument qui renvoie une fonction, alors ça marche en Lisp. Ça marche aussi en C :
Bon, c'est amusant de traduire les choses en C, mais je vais finir par me lasser.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 typedef int _a; typedef int _b; typedef int _c; typedef _b(*_b_to_c)(c); _b_to_c partial_apply(_b_to_c(*f)(_a), _a x) { return f(x); }
Si tu avais parlé de fonctions anonymes et de capture, plutôt que de parler d'application partielle, je crois que tout le monde aurait été d'accord avec toi depuis le début (peut-être la question de terminologie dont parlait Ubiquité).On y arrive, ce que tu appelles capture, j’appelle ça application partielle.
On va dire que tu as clos ce débat avec ce dernier paragraphe. On est enfin d'accord.
Je pars sur le cas deux arguments, car c'est celui là qui est intéressant.
En LISP je te construis en me marrant une fonction avec l'un des deux arguments << capturé >> comme vous dites (je te le fais en haskell n'ayant plus fait de lisp depuis longtemps, mais cela se traduit aisément).
En C tu vas en chier, on est d'accord, et c'est exactement ce point là que je mets en avant pour dire que C n'est pas un langage fonctionnel, car justement c'est de l'application partielle et c'est exactement ce qui fait que personne ne classe le C comme langage fonctionnel.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 apply_first :: (('a, 'b) -> 'c) -> 'a -> 'b -> 'c apply_first f x y = f (x, y) --apply_first f x = \y -> f (x, y)
Je dois avoir une mauvaise mémoire mais je ne me souviens pas t'avoir contredit la dessus.
Même si effectivement je pense que C n'est pas qu'une micro couche au dessus de l'assembleur (je renvoie au message de LLB pour plus d'info là dessus), je ne vois pas où j'ai parlé de ce point ici (à part le présent message bien entendu).
Oui bien sur que c'est possible puisque Lisp supporte les fermetures, fonctions de première classe, etc.
Personne ne prétends le contraire et un exemple a été donné précédemment.
Par contre il n'y a pas en Lisp le sucre syntaxique ni de mécanisme particulier permettant d'appeler avec un argument une fonction qui en attends deux et l'utilisation d'une fonction développé pour renvoyer la fermeture qui va bien ne peut pas être appelée avec les deux arguments en utilisant la syntaxe traditionnel des appels à n arguments.
Je pense que tu gagnerais vraiment à utiliser la terminologie usuelle pour communiquer.
Je serais d'accord s'il y avait une terminologie usuelle, clairement définie, sans mot en triple voir en quadruple. Pour l'instant l'informatique est jeune, fougueuse et en terme de vocabulaire personne n'est d'accord. Et dans notre cas on était exactement dans un débat terminologique (pardonnez moi ce mot) sur savoir quel sens donné au mot fonctionnel. Presque aucun mot aujourd'hui n'a de définition précise qui survit à un examen en profondeur. Tant que l'on aura pas fixé une terminologie on verra ce genre de débats ad vitam eternam.
Correction : les mots que tu emploies ("langage fonctionnel", "application partielle", "géré par l'assembleur") sont vides de sens. Les mots utilisés par la plupart des autres intervenants ("curryfication", "fermeture/closure", "environnement", "sucre syntaxique", "fonctions de première classe") ont un sens précis qui fait consensus.
Bon, d'accord, peut-être pas "sucre syntaxique" (transformation que l'on peut exprimer comme une simple substitution locale ?).
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager