Qu'est-ce que la transparence référentielle?


285

Que signifie le terme transparence référentielle ? Je l'ai entendu décrit comme «cela signifie que vous pouvez remplacer des égaux par des égaux», mais cela semble être une explication inadéquate.


1
wow je me demande pourquoi la soudaine augmentation de la popularité de cette question ...
Claudiu

1
@claudia: Je ne peux pas le dire avec certitude, mais r / haskell a eu du vent et beaucoup pensaient qu'Uday était, bien que très précis, en train de faire un peu de jibe à la communauté.
efrey

6
@efrey Un empannage, peut-être. Mais, lorsque les programmeurs fonctionnels abattent les langages de programmation impératifs et les langages fonctionnels à effets secondaires (comme Lisp et ML) affirmant qu'ils ne sont pas référentiellement transparents, ne prennent-ils pas un empannage? Ne devraient-ils pas au moins avoir raison avant de le faire?
Uday Reddy

2
@Claudiu Je l'ai posté sur Haskell Reddit et Conal l'a tweeté. J'ai trouvé la discussion intéressante et j'ai pensé qu'elle méritait une discussion plus large. J'ai attiré l'attention sur le jibe d'Uday pour stimuler une discussion. Je suis d'accord que nous, les FPers, pouvons parfois faire preuve de complaisance et avoir besoin d'une bonne prod - bravo à Uday pour l'avoir fourni!
chrisdornan

7
@efrey. En effet, c'est pourquoi j'ai choisi de citer Bird et Wadler (sémantistes?) Dans mon deuxième post. Les personnes bien informées savent que la conception populaire de la transparence référentielle est vague et peut-être incohérente. Mais cela n'a jamais été expliqué correctement à la communauté de la programmation. J'espère que mon écriture ici fera une différence.
Uday Reddy

Réponses:


362

Le terme «transparence référentielle» vient de la philosophie analytique , la branche de la philosophie qui analyse les constructions, les déclarations et les arguments du langage naturel basés sur les méthodes de la logique et des mathématiques. En d'autres termes, c'est le sujet le plus proche en dehors de l'informatique de ce que nous appelons la sémantique du langage de programmation . Le philosophe Willard Quine était responsable de l'initiation du concept de transparence référentielle, mais il était également implicite dans les approches de Bertrand Russell et Alfred Whitehead.

À la base, la "transparence référentielle" est une idée très simple et claire. Le terme «référent» est utilisé en philosophie analytique pour parler de la chose à laquelle une expression fait référence . C'est à peu près la même chose que ce que nous entendons par «sens» ou «dénotation» dans la sémantique du langage de programmation. En utilisant l'exemple d'Andrew Birkett ( article de blog ), le terme «la capitale de l'Écosse» fait référence à la ville d'Édimbourg. C'est un exemple simple de "référent".

Un contexte dans une phrase est "référentiellement transparent" si le remplacement d'un terme dans ce contexte par un autre terme qui fait référence à la même entité ne change pas le sens. Par exemple

Le Parlement écossais se réunit dans la capitale de l'Écosse.

signifie la même chose que

Le Parlement écossais se réunit à Édimbourg.

Le contexte "Le Parlement écossais se réunit dans ..." est donc un contexte référentiellement transparent. Nous pouvons remplacer «la capitale de l'Écosse» par «Édimbourg» sans en altérer le sens. En d'autres termes, le contexte ne se soucie que de ce à quoi le terme fait référence et de rien d'autre. C'est dans ce sens que le contexte est «référentiellement transparent».

D'un autre côté, dans la phrase,

Édimbourg est la capitale de l'Écosse depuis 1999.

nous ne pouvons pas faire un tel remplacement. Si nous le faisions, nous obtiendrions "Édimbourg est Édimbourg depuis 1999", ce qui est une chose folle à dire, et ne donne pas le même sens que la phrase d'origine. Il semblerait donc que le contexte "Édimbourg a été ... depuis 1999" est référentiellement opaque (l'opposé de référentiellement transparent). Il se soucie apparemment de quelque chose de plus que ce à quoi le terme fait référence. Qu'Est-ce que c'est?

Des choses telles que «la capitale de l'Écosse» sont appelées des termes définis et elles n'ont pas donné de mal de tête aux logiciens et aux philosophes pendant longtemps. Russell et Quine les ont classés en disant qu'ils ne sont pas réellement "référentiels", c'est-à-dire que c'est une erreur de penser que les exemples ci-dessus sont utilisés pour faire référence à des entités. La bonne façon de comprendre "Édimbourg est la capitale de l'Écosse depuis 1999", c'est-à-dire

L'Écosse a une capitale depuis 1999 et cette capitale est Édimbourg.

Cette phrase ne peut pas être transformée en une phrase folle. Problème résolu! Le but de Quine était de dire que le langage naturel est désordonné, ou du moins compliqué, parce qu'il est conçu pour être pratique à utiliser, mais les philosophes et les logiciens devraient apporter de la clarté en les comprenant correctement. La transparence référentielle est un outil à utiliser pour apporter une telle clarté de sens .

Qu'est-ce que tout cela a à voir avec la programmation? Pas vraiment, en fait. Comme nous l'avons dit, la transparence référentielle est un outil à utiliser pour comprendre le langage, c'est-à-dire pour attribuer un sens . Christopher Strachey , qui a fondé le domaine de la sémantique des langages de programmation, l'a utilisé dans son étude du sens. Son document de base " Concepts fondamentaux dans les langages de programmation " est disponible sur le Web. C'est un beau papier et tout le monde peut le lire et le comprendre. Alors, faites-le. Vous serez très éclairé. Il introduit le terme "transparence référentielle" dans ce paragraphe:

L'une des propriétés les plus utiles des expressions est celle appelée par transparence référentielle Quine. En substance, cela signifie que si nous voulons trouver la valeur d'une expression qui contient une sous-expression, la seule chose que nous devons savoir sur la sous-expression est sa valeur. Toutes les autres caractéristiques de la sous-expression, telles que sa structure interne, le nombre et la nature de ses composants, l'ordre dans lequel ils sont évalués ou la couleur de l'encre dans laquelle ils sont écrits, ne sont pas pertinents pour la valeur du principal expression.

L'utilisation de "en substance" suggère que Strachey le paraphrase afin de l'expliquer en termes simples. Les programmeurs fonctionnels semblent comprendre ce paragraphe à leur manière. Il y a 9 autres occurrences de "transparence référentielle" dans le document, mais elles ne semblent pas se soucier des autres. En fait, tout l'article de Strachey est consacré à expliquer la signification des langages de programmation impératifs . Mais, aujourd'hui, les programmeurs fonctionnels affirment que les langages de programmation impératifs ne sont pas référentiellement transparents. Strachey se retournerait dans sa tombe.

Nous pouvons sauver la situation. Nous avons dit que le langage naturel est "désordonné, ou du moins compliqué" car il est conçu pour être pratique à utiliser. Les langages de programmation sont de la même manière. Ils sont "désordonnés, ou au moins compliqués" car ils sont conçus pour être pratiques pour une utilisation pratique. Cela ne signifie pas qu'ils doivent nous confondre. Il suffit de les comprendre de la bonne façon, en utilisant un méta-langage qui est référentiellement transparent pour que nous ayons une clarté de sens. Dans l'article que j'ai cité, Strachey fait exactement cela. Il explique la signification des langages de programmation impératifs en les décomposant en concepts élémentaires, sans jamais perdre de clarté nulle part. Une partie importante de son analyse est de souligner que les expressions dans les langages de programmation ont deux types de "valeurs",valeurs r . Avant l'article de Strachey, cela n'était pas compris et la confusion régnait en maître. Aujourd'hui, la définition de C le mentionne régulièrement et chaque programmeur C comprend la distinction. (Il est difficile de dire si les programmeurs dans d'autres langues le comprennent aussi bien.)

Quine et Strachey étaient tous deux concernés par la signification des constructions de langage qui impliquent une certaine forme de dépendance au contexte. Par exemple, notre exemple "Édimbourg est la capitale de l'Écosse depuis 1999" signifie que la "capitale de l'Écosse" dépend du moment où elle est considérée. Cette dépendance au contexte est une réalité, à la fois dans les langages naturels et les langages de programmation. Même dans la programmation fonctionnelle, les variables libres et liées doivent être interprétées en fonction du contexte dans lequel elles apparaissent. La dépendance du contexte de tout type bloque la transparence référentielle d'une manière ou d'une autre. Si vous essayez de comprendre le sens des termes sans tenir compte des contextes dont ils dépendent, vous vous retrouverez à nouveau dans la confusion. Quine était préoccupé par le sens de la logique modale. Il a soutenu quela logique modale était référentiellement opaque et devrait être nettoyée en la traduisant en un cadre référentiel transparent (par exemple, en considérant la nécessité comme la prouvabilité). Il a largement perdu ce débat. Les logiciens et les philosophes ont trouvé que la sémantique mondiale possible de Kripke était parfaitement adéquate. Une situation similaire règne également avec une programmation impérative. La dépendance à l'État expliquée par Strachey et la dépendance au magasin expliquée par Reynolds (d'une manière similaire à la sémantique mondiale possible de Kripke) sont parfaitement adéquates. Les programmeurs fonctionnels ne connaissent pas grand-chose à cette recherche. Leurs idées sur la transparence référentielle doivent être prises avec un gros grain de sel.

[Note supplémentaire: Les exemples ci-dessus illustrent qu'une expression simple telle que «capitale de l'Écosse» a plusieurs niveaux de signification. À un certain niveau, nous pourrions parler de la capitale à l'heure actuelle. À un autre niveau, nous pourrions parler de toutes les capitales possibles que l'Écosse aurait pu avoir au fil du temps. Nous pouvons «zoomer» sur un contexte particulier et «dézoomer» pour couvrir tous les contextes assez facilement dans la pratique normale. L'efficacité du langage naturel utilise notre capacité à le faire. Les langages de programmation impératifs sont très efficaces de la même manière. Nous pouvons utiliser une variable x sur le côté droit d'une affectation (la valeur r ) pour parler de sa valeur dans un état particulier. Ou, nous pourrions parler de sa valeur lqui couvre tous les États. Les gens sont rarement confondus par de telles choses. Cependant, ils peuvent ou non être capables d'expliquer précisément toutes les couches de sens inhérentes aux constructions langagières. Toutes ces couches de sens ne sont pas nécessairement «évidentes» et il est de la science de les étudier correctement. Cependant, l'inarticulation des gens ordinaires pour expliquer de telles significations en couches n'implique pas qu'ils soient confus à leur sujet.]

Un "post-scriptum" ci-dessous relie cette discussion aux préoccupations de programmation fonctionnelle et impérative .


10
Merci, mais je ne pense pas qu'il existe une notion d'extensionnelle "évidente" de l'égalité. Quand j'ai dit que la "capitale de l'Ecosse" fait référence à la ville d'Edimbourg, vous n'y avez pas réfléchi à deux fois. Mais quand j'ai commencé à parler de "depuis 1999", vous avez soudain pris conscience qu'il y avait du temps. Ainsi, la notion d'extension de l'égalité peut être assez subtile et elle est formalisée par les chercheurs en langage de programmation. Les gens qui veulent avoir une parfaite compréhension de l'égalité extensionnelle doivent apprendre les fruits de cette recherche. Ce n'est peut-être pas du tout «évident».
Uday Reddy

5
Fantastique! Un soulagement bienvenu aux idées fausses populaires sur la RT, par exemple, la relier aux fonctions . Ou définir en remplaçant une expression par sa valeur (comme sur Wikipédia) - étrangement car les expressions et les valeurs sont différentes sortes de choses. Peut-être qu'un endroit où les gens se trompent en considérant la RT-ness des langages impératifs est de supposer que ces "valeurs" sont des choses simples comme les nombres plutôt que des choses plus complexes comme les fonctions d'un magasin.
Conal

13
@sclv Quant à l'impact plus large de la philosophie analytique sur l'informatique, je dois dire que l'informatique, telle que nous la connaissons, a été fondée par Godel, Church, Kleene et Turing. Ces gens étaient des logiciens et ils connaissaient bien les aspects mathématiques et philosophiques de la logique, en particulier les traditions de Peano, Frege, Russell, Whitehead, Carnap et Quine. Les premiers pionniers de l'informatique moderne connaissaient les connexions. Mais la croissance rapide de l'informatique les a coupés. Nous devons y revenir.
Uday Reddy

5
@sclv Logic est traditionnellement interprété comme la science des conséquences . Mais je pense que c'est plus large. C'est la science de l' information . Quine, je vois comme le premier à avoir fait émerger une vision plus large. "Word and object" est une analyse du contenu informationnel des énoncés en langage naturel. Cependant, ni les philosophes ni les mathématiciens ne se sont jamais intéressés activement aux calculs , ce qui est assez déroutant, étant donné la centralité du calcul pour la civilisation et la science depuis des temps immémoriaux. Nous devons trouver des moyens de les intéresser.
Uday Reddy

3
@Conal: J'ai ajouté une nouvelle réponse qui amplifie votre point. Ce sera probablement au bas de la page.
Uday Reddy

134

La transparence référentielle, un terme couramment utilisé dans la programmation fonctionnelle, signifie que, étant donné une fonction et une valeur d'entrée, vous recevrez toujours la même sortie. C'est-à-dire qu'aucun état externe n'est utilisé dans la fonction.

Voici un exemple de fonction transparente référentielle:

int plusOne(int x)
{
  return x+1;
}

Avec une fonction transparente référentielle, étant donné une entrée et une fonction, vous pouvez la remplacer par une valeur au lieu d'appeler la fonction. Ainsi, au lieu d'appeler plusOne avec un paramètre de 5, nous pourrions simplement le remplacer par 6.

Un autre bon exemple est celui des mathématiques en général. En mathématiques, étant donné une fonction et une valeur d'entrée, il correspondra toujours à la même valeur de sortie. f (x) = x + 1. Les fonctions mathématiques sont donc référentiellement transparentes.

Ce concept est important pour les chercheurs car il signifie que lorsque vous avez une fonction référentiellement transparente, elle se prête à une parallélisation et une mise en cache automatiques faciles.

La transparence référentielle est toujours utilisée dans les langages fonctionnels comme Haskell.

-

En revanche, il y a le concept d'opacité référentielle. Cela signifie le contraire. L'appel de la fonction peut ne pas toujours produire la même sortie.

//global G
int G = 10;

int plusG(int x)
{//G can be modified externally returning different values.
  return x + G;
}

Un autre exemple est une fonction membre dans un langage de programmation orienté objet. Les fonctions membres opèrent généralement sur ses variables membres et seraient donc opaques référentielles. Les fonctions des membres peuvent bien sûr être référentiellement transparentes.

Un autre exemple encore est une fonction qui lit à partir d'un fichier texte et imprime la sortie. Ce fichier texte externe pourrait changer à tout moment de sorte que la fonction serait référentiellement opaque.


1
Juste un avertissement, il est possible d'avoir un objet entièrement référentiellement transparent, avec des fonctions membres référentiellement transparentes. Voir okmij.org/ftp/Scheme/oop-in-fp.txt
Jonathan Arkell

1
Et voici le code dont il est question dans cet article: okmij.org/ftp/Scheme/pure-oo-system.scm
Jonathan Arkell

Dans le cas d'une classe entièrement référentiellement transparente, vous auriez probablement toutes les fonctions membres statiques.
Brian R. Bondy

13
Ce dont vous parlez ici n'est pas la transparence référentielle, bien que ce soit communément appelé comme tel. Voir les deux réponses d'Uday et leurs commentaires. En particulier, ce que vous appelez la "sortie" n'est pas la dénotation. Si vous remplacez "plusG 3" par toute autre expression ayant la même valeur / dénotation, vous obtiendrez en effet un programme avec la même signification, donc RT tient dans les langages impératifs. Les expressions "3 + 10" ou "13" n'ont pas la même signification que "plusG 3", car la signification dans les langues impératives est fonction du "magasin" (état).
Conal

1
Je viens de lire un article sur les effets secondaires et le changement d'état et j'ai l'intuition que cela a quelque chose à voir avec la RT. Pourriez-vous ajouter une note à ce sujet?
Gaurav

91

Une fonction référentiellement transparente est une fonction qui ne dépend que de son entrée.


4
C'est pourquoi c'est difficile en programmation OO car les objets ont un état.
Kris

5
Est-il donc exact de dire que «référentiellement transparent» est identique à «déterministe» lors de la description des fonctions? Sinon, quelle est la différence entre les deux termes?
mwolfe02

1
Cela ressemble aussi à une définition d'une fonction "pure".
Evgeny A.

75

[Ceci est un post-scriptum de ma réponse du 25 mars, dans un effort pour rapprocher la discussion des préoccupations de programmation fonctionnelle / impérative.]

L'idée des programmeurs fonctionnels de la transparence référentielle semble différer de la notion standard de trois manières:

  • Alors que les philosophes / logiciens utilisent des termes comme "référence", "dénotation", "designatum" et " bedeutung " (terme allemand de Frege), les programmeurs fonctionnels utilisent le terme "valeur". (Ce n'est pas entièrement de leur fait. Je remarque que Landin, Strachey et leurs descendants ont également utilisé le terme "valeur" pour parler de référence / dénotation. Il peut s'agir simplement d'une simplification terminologique que Landin et Strachey ont introduite, mais il semble grande différence lorsqu'il est utilisé de manière naïve.)

  • Les programmeurs fonctionnels semblent croire que ces "valeurs" existent à l'intérieur du langage de programmation, pas à l'extérieur. Ce faisant, ils diffèrent à la fois des philosophes et des sémantistes du langage de programmation.

  • Ils semblent croire que ces "valeurs" sont censées être obtenues par évaluation.

Par exemple, l'article de Wikipedia sur la transparence référentielle dit ce matin:

Une expression est dite référentiellement transparente si elle peut être remplacée par sa valeur sans changer le comportement d'un programme (en d'autres termes, produire un programme qui a les mêmes effets et qui sort sur la même entrée).

Ceci est complètement en contradiction avec ce que disent les philosophes / logiciens. Ils disent qu'un contexte est référentiel ou référentiellement transparent si une expression dans ce contexte peut être remplacée par une autre expression qui fait référence à la même chose (une expression coréférentielle ). Qui sont ces philosophes / logiciens? Ils comprennent Frege , Russell , Whitehead , Carnap , Quine , Churchet d'innombrables autres. Chacun d'eux est une figure imposante. La puissance intellectuelle combinée de ces logiciens est pour le moins bouleversante. Tous sont unanimes dans la position selon laquelle les référents / dénotations existent en dehors du langage formel et les expressions dans le langage ne peuvent que parler d' eux. Ainsi, tout ce que l'on peut faire dans le langage est de remplacer une expression par une autre expression qui fait référence à la même entité. Les référents / dénotations eux - mêmes n'existent pas dans la langue. Pourquoi les programmeurs fonctionnels s'écartent-ils de cette tradition bien établie?

On pourrait supposer que les sémantistes du langage de programmation peuvent les avoir induits en erreur. Mais ils ne l'ont pas fait.

Landin :

(a) chaque expression a une structure de sous-expression imbriquée, (b) chaque sous-expression dénote quelque chose (généralement un nombre, une valeur de vérité ou une fonction numérique) , (c) la chose qu'une expression dénote, c'est-à-dire sa "valeur", ne dépend que de la valeurs de ses sous-expressions, et non sur leurs autres propriétés. [Accent ajouté]

Stoy :

La seule chose qui compte dans une expression est sa valeur, et toute sous-expression peut être remplacée par toute autre valeur égale [Accentuation ajoutée]. De plus, la valeur d'une expression est, dans certaines limites, la même chaque fois qu'elle se produit ".

Oiseau et échassier :

la valeur d'une expression ne dépend que des valeurs de ses expressions constituantes (le cas échéant) et ces sous-expressions peuvent être remplacées librement par d' autres possédant la même valeur [Soulignement ajouté].

Ainsi, rétrospectivement, les efforts de Landin et Strachey pour simplifier la terminologie en remplaçant «référence» / «dénotation» par «valeur» auraient pu être peu judicieux. Dès que l'on entend parler d'une "valeur", on est tenté de penser à un processus d'évaluation qui y conduit. Il est également tentant de considérer ce que l'évaluation produit comme la "valeur", même s'il peut être tout à fait clair que ce n'est pas la dénotation. C'est ce que je pense être arrivé au concept de «transparence référentielle» aux yeux des programmeurs fonctionnels. Mais la "valeur" dont parlaient les premiers sémantistes n'est pas le résultat d'une évaluation ou la sortie d'une fonction ou quelque chose de ce genre. C'est la dénotation du terme.

Une fois que nous comprenons la soi-disant "valeur" d'une expression ("référence" ou "dénotation" dans le discours des philosophes classiques) comme un objet mathématique / conceptuel complexe, toutes sortes de possibilités s'ouvrent.

  • Strachey a interprété les variables dans les langages de programmation impératifs comme des valeurs L , comme mentionné dans ma réponse du 25 mars, qui est un objet conceptuel sophistiqué qui n'a pas de représentation directe dans la syntaxe d'un langage de programmation.
  • Il a également interprété des commandes dans des langages comme des fonctions d'état à état, une autre instance d'un objet mathématique complexe qui n'est pas une "valeur" dans la syntaxe.
  • Même un appel de fonction à effets secondaires en C a une "valeur" bien définie en tant que transformateur d'état qui mappe les états à des paires d'états et de valeurs (ce que l'on appelle la "monade" dans la terminologie des programmeurs fonctionnels).

La réticence des programmeurs fonctionnels à appeler de tels langages "référentiellement transparents" implique simplement qu'ils sont réticents à admettre des objets mathématiques / conceptuels complexes comme des "valeurs". D'un autre côté, ils semblent parfaitement disposés à appeler un transformateur d'état une "valeur" lorsqu'il est placé dans leur propre syntaxe préférée et habillé avec un mot à la mode comme "monade". Je dois dire qu'ils sont totalement incohérents, même si nous leur accordons que leur idée de «transparence référentielle» a une certaine cohérence.

Un peu d'histoire pourrait éclairer la façon dont ces confusions ont vu le jour. La période entre 1962 et 1967 a été très intense pour Christopher Strachey. Entre 1962 et 1965, il a pris un emploi à temps partiel en tant qu'assistant de recherche chez Maurice Wilkes pour concevoir et mettre en œuvre le langage de programmation qui allait devenir le CPL. Il s'agissait d'un langage de programmation impératif, mais devait également disposer de puissantes capacités de langage de programmation fonctionnel. Landin, qui était un employé de Strachey dans sa société de conseil, a eu une énorme influence sur la vision de Strachey des langages de programmation. Dans le document de référence de 1965 " Les 700 prochains langages de programmation ", Landin promeut sans vergogne les langages de programmation fonctionnels (les appelant dénotatifslangages) et décrit les langages de programmation impératifs comme leur "antithèse". Dans la discussion qui a suivi, nous constatons que Strachey soulève des doutes sur la position forte de Landin.

... Les DL forment un sous-ensemble de toutes les langues. Ils constituent un sous-ensemble intéressant, mais qui n'est pas pratique à utiliser, sauf si vous y êtes habitué. Nous en avons besoin car pour le moment nous ne savons pas construire des preuves avec des langages qui incluent impératifs et sauts. [Accent ajouté]

En 1965, Strachey a pris la position d'un lecteur à Oxford et semble avoir travaillé essentiellement à plein temps sur le développement d'une théorie des impératifs et des sauts. En 1967, il était prêt avec une théorie, qu'il a enseignée dans son cours sur " Les concepts fondamentaux dans les langages de programmation " dans une école d'été de Copenhague. Les notes de cours étaient censées avoir été publiées, mais "malheureusement, en raison d'une révision dilatoire, les procédures ne se sont jamais concrétisées; cependant, comme une grande partie du travail de Strachey à Oxford, le journal a eu une circulation privée influente". ( Martin Campbell-Kelly )

La difficulté d'obtenir les écrits de Strachey aurait pu conduire à la propagation des confusions, les gens s'appuyant sur des sources secondaires et du ouï-dire. Mais, maintenant que les « concepts fondamentaux » sont facilement disponibles sur le Web, il n'est plus nécessaire de recourir à des devinettes. Nous devons le lire et nous faire une idée de ce que Strachey voulait dire. En particulier:

  • Dans la section 3.2, il traite des "expressions" où il parle de "transparence référentielle de la valeur R".
  • Sa section 3.3 traite des «commandes» où il parle de «transparence référentielle de valeur L».
  • Dans la section 3.4.5, il parle de "fonctions et routines" et déclare que "tout écart de transparence référentielle de valeur R dans un contexte de valeur R devrait être éliminé en décomposant l'expression en plusieurs commandes et expressions plus simples, ou, si cela s'avère difficile, fait l'objet d'un commentaire. "

Toute discussion sur la "transparence référentielle" sans comprendre la distinction entre les valeurs L, les valeurs R et d'autres objets complexes qui peuplent l'univers conceptuel du programmeur impératif est fondamentalement erronée.


10
Je pense qu'il vaut la peine de souligner que confondre ces deux notions de «valeur» (évaluations vs dénotations) induit en erreur les programmeurs fonctionnels dans leur critique des langages impératifs , où l'écart entre les notions est important.
Conal

8
c'est-à-dire que la notion d'évaluation conduit à la conclusion que les langages impératifs ne sont pas des RT, contrairement à la notion de dénotation.
Conal

12
Il me semble qu'une fois que vous avez vraiment complètement cloué la sémantique dénotationnelle d'un langage, cela ne peut qu'être référentiel transparent. Cela semble donc équivaloir à dire que le terme n'est pas utile en ce qui concerne les langages de programmation.
Tom Crockett

20
Il semble donc que les gens ont l'habitude d'utiliser un terme pour signifier quelque chose de sensiblement différent de ce que les autres ont voulu dire lorsqu'ils ont utilisé ce terme dans le passé. À quoi je dis: Bienvenue dans la langue anglaise.
Daniel Pratt

17
@DanielPratt: Si la liberté des effets secondaires est ce que veulent dire les programmeurs fonctionnels, pourquoi l'appellent-ils "transparence référentielle"? Ils peuvent simplement l'appeler "liberté des effets secondaires", ce qui est une idée parfaitement claire. Personne sur n'aura besoin de demander sur stackexchange ce que signifie "liberté d'effet secondaire". Où est la nécessité de dérober des termes classiques grandioses que personne ne semble comprendre?
Uday Reddy

23

Une expression est référentiellement transparente si elle peut être remplacée par sa valeur, sans changer l'algorithme, produisant un algorithme qui a les mêmes effets et qui sort sur la même entrée.


18

Une fonction référentiellement transparente est une fonction qui agit comme une fonction mathématique; étant donné les mêmes entrées, il produira toujours les mêmes sorties. Cela implique que l'état transmis n'est pas modifié et que la fonction n'a pas d'état propre.


10

Pour ceux qui ont besoin d'une explication concise, j'en risquerai une (mais lisez la divulgation ci-dessous).

La transparence référentielle dans un langage de programmation favorise le raisonnement équationnel - plus vous avez de transparence référentielle, plus il est facile de faire un raisonnement équationnel. Par exemple avec une (pseudo) définition de fonction,

fx = x + x,

la facilité avec laquelle vous pouvez (en toute sécurité) remplacer f (foo) par foo + foo dans le cadre de cette définition, sans avoir trop de contraintes sur l'endroit où vous pouvez effectuer cette réduction, est une bonne indication de la transparence référentielle de votre langage de programmation a.

Par exemple, si foo était x ++ au sens de la programmation C, vous ne pourriez pas effectuer cette réduction en toute sécurité (c'est-à-dire que si vous effectuez cette réduction, vous ne vous retrouveriez pas avec le même programme que celui avec lequel vous avez commencé).

Dans les langages de programmation pratiques, vous ne verrez pas une transparence référentielle parfaite, mais les programmeurs fonctionnels s'en soucient plus que la plupart (cf. Haskell, où c'est un objectif central).

(Divulgation complète: je suis un programmeur fonctionnel, donc par la réponse la plus élevée, vous devriez prendre cette explication avec un grain de sel.)


3
Je n'ai aucun problème avec les langues facilitant le raisonnement équationnel. Mais je contesterais que cela a quelque chose à voir avec la "transparence référentielle" telle que définie classiquement. Deuxièmement, en tant que programmeur pratique, je pense que le raisonnement équationnel est surfait. Le raisonnement qui est important dans la pratique concerne les conditions préalables, les conditions postérieures, les invariants et l'abstraction des données. Pour les personnes qui s'appuient sur de telles techniques de raisonnement, les effets secondaires ne semblent pas avoir beaucoup d'importance. Donc, bien que je convienne avec vous que les effets secondaires dans les expressions sont une mauvaise idée, ils ne semblent pas représenter un argument tueur.
Uday Reddy

1
@UdayReddy Tout simplement parce que les programmeurs fonctionnels ont choisi une méthode particulière pour établir la transparence référentielle dans leurs programmes (éliminer les effets secondaires et développer une algèbre sophistiquée et puissante de programmes), ou parce que certains praticiens ne comprennent probablement pas aussi bien la transparence référentielle que ils pensent qu'ils le font, ne signifie pas que les langages de programmation fonctionnels ne parviennent pas à augmenter la transparence référentielle ou que les programmeurs de langage fonctionnel et les rédacteurs de compilateurs n'exploitent pas cette augmentation de la tractabilité formelle à de nombreuses fins.
chrisdornan

2
Chris: Uday a souligné que Strachey éliminait le problème de l'opacité référentielle dans la sémantique des langages de programmation, en particulier pour les langages impératifs. Les programmeurs fonctionnels ne peuvent donc pas "composer la transparence référentielle dans leurs programmes". À titre d'exemple concret, Haskell IO n'est d'aucune aide avec RT, car aucune aide RT n'est nécessaire.
Conal

2
@chrisdornan: Désolé pour mon premier commentaire ci-dessus. J'ai moi-même eu du mal à comprendre ce que j'essayais de dire dans les deux premières phrases :-( Mais, voici une explication. Considérons un calcul de mise en scène à deux niveaux ou à plusieurs niveaux. Chaque opérateur de mise en scène est référentiellement opaque. Il est en fait ., un opérateur de cotation Cependant, vous pouvez le faire raisonnement équationnel à chaque étape parfaitement bien Ainsi, chaque opérateur référentielle opaque mis en place des limites pour le raisonnement equational Mais vous avez encore raisonnement équationnel dans ces limites...
Uday Reddy

1
@chrisdomain: De plus, très peu de gens voudraient être des puristes référentiels de la transparence afin de bannir de tels opérateurs de mise en scène. Ces opérateurs sont extrêmement utiles. La programmation sans eux en effectuant la mise en scène manuellement serait fastidieuse, sujette aux erreurs et laide. Et, la mise en scène manuelle ne vous achèterait pas plus de raisonnement équationnel que ce que vous aviez auparavant. Ainsi, interdire de bons dispositifs de programmation dans la poursuite puriste du raisonnement équationniste reviendrait à se couper le nez pour contrarier votre visage.
Uday Reddy

8

Si vous êtes intéressé par l'étymologie (c.-à-d. Pourquoi ce concept a-t-il ce nom particulier), jetez un œil à mon article de blog sur le sujet. La terminologie vient du philosophe / logicien Quine.


4
  1. La sémantique dénotationnelle est basée sur la modélisation des langages en construisant des domaines qui constituent des valeurs dénotables .
  2. Les programmeurs fonctionnels utilisent le terme valeur pour décrire la convergence d'un calcul basé sur les règles de réécriture du langage ie. sa sémantique opérationnelle.

Dans 1, il y a une clarté de deux langues en question:

  • celui qui est modélisé, le langage objet
  • le langage de la modélisation, le méta langage

En 2, grâce à la proximité de l'objet et des métalangages, ils peuvent être confondus.

En tant qu'implémenteur de langage, je trouve que je dois constamment me souvenir de cette distinction.

Alors, le professeur Reddy, je peux vous paraphraser ainsi :-)

Dans les contextes de programmation fonctionnelle et de sémantique, le terme Transparence Référentielle n'est pas référentiellement transparent.


1
Ha ha. Merci pour l'explication. Le problème est également que les programmeurs fonctionnels agissent comme s'ils avaient une notion générale de "transparence référentielle" qui est applicable à tous les langages de programmation . Mais cela dépend de leur notion de «valeur», qui peut ou non avoir un sens pour d'autres langues. Pour revendiquer une théorie générale de la "transparence référentielle", ils doivent produire une "valeur" de théorie générale. Cela fait défaut jusqu'à présent.
Uday Reddy

4

J'espère que la réponse suivante complète et qualifie les 1ère et 3e réponses controversées.

Admettons qu'une expression désigne ou fasse référence à un référent. Cependant, la question est de savoir si ces référents peuvent être codés de manière isomorphe dans le cadre des expressions elles-mêmes, appelant ces expressions des «valeurs». Par exemple, les valeurs de nombres littéraux sont un sous-ensemble de l'ensemble d'expressions arithmétiques, les valeurs de vérité sont un sous-ensemble de l'ensemble d'expressions booléennes, etc. L'idée est d'évaluer une expression à sa valeur (si elle en a une). Ainsi, le mot «valeur» peut faire référence à une dénotation ou à un élément distinctif de l'ensemble d'expressions. Mais s'il y a un isomorphisme (une bijection) entre le référent et la valeur on peut dire que c'est la même chose. (Cela dit, il faut faire attention à définir les référents et l'isomorphisme, comme le prouve le domaine de la sémantique dénotationnelle. Pour mettre un exemple mentionné par les réponses à la 3ème réponse,data Nat = Zero | Suc Nat ne correspond pas comme prévu à l'ensemble des nombres naturels.)

Écrivons E[·]pour une expression avec un trou, également connu dans certains milieux comme un «contexte». Deux exemples de contexte pour les expressions de type C sont [·]+1et [·]++.

Écrivons [[·]]pour la fonction qui prend une expression (sans trou) et délivre sa signification (référent, dénotation, etc.) dans un univers fournissant du sens. (J'emprunte la notation au domaine de la sémantique dénotationnelle.)

Adaptons quelque peu la définition de Quine de la manière suivante: un contexte E[·] est référentiellement transparent si deux expressions E1et E2(pas de trous là-bas) telles que [[E1]] = [[E2]](c'est-à-dire les expressions dénotent / se réfèrent au même référent) alors c'est le cas qui [[E[E1]]] = [[E[E2]]](ie remplissant -dans le trou avec soit E1ou E2donne des expressions qui désignent également le même référent).

La règle de Leibniz de substituer des égaux aux égaux est généralement exprimée comme «si E1 = E2alors E[E1] = E[E2]», ce qui dit que E[·]c'est une fonction. Une fonction (ou d'ailleurs un programme calculant la fonction) est un mappage d'une source à une cible de sorte qu'il y ait au plus un élément cible pour chaque élément source. Les fonctions non déterministes sont misnomères, ils sont des relations, les fonctions ensembles livrent, etc. Si dans la règle de Leibniz l'égalité =est dénotation alors les doubles crochets sont simplement pris pour acquis et élision. Un contexte référentiellement transparent est donc une fonction. Et la règle de Leibniz est l'ingrédient principal du raisonnement équationnel, de sorte que le raisonnement équationnel est définitivement lié à la transparence référentielle.

Bien que ce [[·]]soit une fonction des expressions aux dénotations, cela pourrait être une fonction des expressions aux «valeurs» comprises comme un sous-ensemble restreint d'expressions, et [[·]]peut être comprise comme une évaluation.

Maintenant, si E1est une expression et E2est une valeur, nous avons ce que je pense que la plupart des gens entendent par la définition de la transparence référentielle en termes d'expressions, de valeurs et d'évaluation. Mais comme l'illustrent les 1ère et 3ème réponses de cette page, il s'agit d'une définition inexacte.

Le problème avec des contextes tels que [·]++n'est pas l'effet secondaire, mais que sa valeur n'est pas définie en C de manière isomorphe à sa signification. Les fonctions ne sont pas des valeurs (enfin, les pointeurs vers les fonctions le sont), contrairement aux langages de programmation fonctionnels. Landin, Strachey et les pionniers de la sémantique dénotationnelle ont été assez intelligents dans l'utilisation des mondes fonctionnels pour donner du sens.

Pour les langages impératifs de type C, nous pouvons (grossièrement) fournir la sémantique aux expressions utilisant la fonction [[·]] : Expression -> (State -> State x Value).

Valueest un sous-ensemble de Expression. Statecontient des paires (identifiant, valeur). La fonction sémantique prend une expression et délivre comme sens une fonction de l'état actuel à la paire avec l'état mis à jour et une valeur. Par exemple, [[x]]est la fonction de l'état actuel à la paire dont le premier composant est l'état actuel et dont le deuxième composant est la valeur de x. En revanche, [[x++]]est la fonction de l'état actuel à la paire dont le premier composant est un état dans lequel la valeur de x est incrémentée, et dont le deuxième composant est cette même valeur. En ce sens, le contexte [·]++est référentiellement transparent s'il satisfait à la définition donnée ci-dessus.

Je pense que les programmeurs fonctionnels ont le droit d'utiliser la transparence référentielle dans le sens où ils récupèrent naturellement [[·]]en fonction des expressions aux valeurs. Les fonctions sont des valeurs de première classe et l'état peut également être une valeur, pas une dénotation. La monade d'état est (en partie) un mécanisme propre pour passer (ou enfiler) l'état.


Vraisemblablement, les réponses «1er» et «3e» sont respectivement les réponses «25 mars» et «postscript» d'UdayReddy. Les ordinaux ne sont pas un bon moyen de se référer aux réponses dans SO. Non seulement les votes et les acceptations peuvent changer au fil du temps, mais il existe plusieurs commandes sélectionnables.
philipxy

2

Notez que ce concept de «sens» est quelque chose qui se passe dans l'esprit de l'observateur. Ainsi, la même "référence" peut signifier différentes choses pour différentes personnes. Ainsi, par exemple, nous avons une page de désambiguïsation à Édimbourg sur Wikipedia.

Un problème connexe qui peut apparaître dans le contexte de la programmation pourrait être le polymorphisme.

Et peut-être devrions-nous avoir un nom pour le cas spécial du polymorphisme (ou peut-être même de la coulée) où, pour nos besoins, les différents cas polymorphes sont sémantiquement équivalents (par opposition à être simplement similaires. Par exemple, le nombre 1 - qui pourrait être représenté en utilisant un type entier, ou un type complexe ou n'importe lequel d'une variété d'autres types - peut être traité de manière polymorphe).


0

J'ai trouvé utile la définition de la transparence référentielle dans le livre " Structure and Implementation of Computer Programs " (le Wizard Book) car elle est complétée par une explication de la façon dont la transparence référentielle est violée en introduisant l' opération d'affectation . Découvrez le jeu de diapositives suivant que j'ai réalisé sur le sujet: https://www.slideshare.net/pjschwarz/introducing-assignment-invalidates-the-substitution-model-of-evaluation-and-violates-referential-transparency-as- expliqué dans sicp-the-wizard-book


0

La transparence référentielle peut être simplement énoncée comme:

  • Une expression évaluant toujours le même résultat dans n'importe quel contexte [1] ,
  • Une fonction, si elle reçoit deux fois les mêmes paramètres, doit produire deux fois le même résultat [2] .

Par exemple, le langage de programmation Haskell est un langage fonctionnel pur; ce qui signifie qu'il est référentiellement transparent.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.