J'ai vu cela dans des paradigmes impératifs
f (x) + f (x)
pourrait ne pas être la même chose que:
2 * f (x)
Mais dans un paradigme fonctionnel, cela devrait être la même chose. J'ai essayé d'implémenter les deux cas en Python et Scheme , mais pour moi, ils ont l'air assez simples.
Quel serait un exemple qui pourrait indiquer la différence avec la fonction donnée?
f(x++)+f(x++)
peut-être pas la même chose que2*f(x++)
(en C, c'est particulièrement beau quand des choses comme celles-là sont cachées dans des macros - est-ce que je me suis cassé le nez là-dessus? pariez-vous)f(x++)+f(x++)
peut être absolument n'importe quoi, puisqu'il invoque un comportement indéfini. Mais cela n’est pas vraiment lié à la transparence référentielle - ce qui n’aiderait pas cet appel, il est «indéfini» pour les fonctions référentiellement transparentes comme dans le cassin(x++)+sin(x++)
contraire. Pourrait être 42, pourrait formater votre disque dur, pourrait avoir des démons voler sur le nez des utilisateurs…Réponses:
La transparence référentielle, associée à une fonction, indique que vous pouvez déterminer le résultat de l'application de cette fonction uniquement en consultant les valeurs de ses arguments. Vous pouvez écrire des fonctions référentiellement transparentes dans n’importe quel langage de programmation, par exemple Python, Scheme, Pascal, C.
Par ailleurs, dans la plupart des langues, vous pouvez également écrire des fonctions non transparentes par référentiel. Par exemple, cette fonction Python:
n'est pas référentiellement transparent, appelant en fait
et
produira des valeurs différentes, pour tout argument
x
. La raison en est que la fonction utilise et modifie une variable globale. Par conséquent, le résultat de chaque invocation dépend de cet état changeant, et pas seulement de l'argument de la fonction.Haskell, un langage purement fonctionnel, sépare strictement l' évaluation de l'expression dans laquelle des fonctions pures sont appliquées et qui est toujours transparente de manière référentielle, de l' exécution de l' action (traitement des valeurs spéciales), qui n'est pas transparente de manière référentielle, c'est-à-dire que l'exécution de la même action peut avoir à chaque fois une résultat différent.
Donc, pour toute fonction Haskell
et tout entier
x
, il est toujours vrai queUn exemple d'action est le résultat de la fonction de bibliothèque
getLine
:À la suite de l'évaluation de l'expression, cette fonction (en fait une constante) produit tout d'abord une valeur pure de type
IO String
. Les valeurs de ce type sont des valeurs comme les autres: vous pouvez les transmettre, les placer dans des structures de données, les composer à l'aide de fonctions spéciales, etc. Par exemple, vous pouvez faire une liste d'actions comme ceci:Les actions ont ceci de particulier que vous pouvez demander à l'exécution de Haskell de les exécuter en écrivant:
Dans ce cas, lorsque votre programme Haskell est démarré, le moteur d'exécution parcourt l'action qui lui est liée
main
et l' exécute , produisant éventuellement des effets secondaires. Par conséquent, l'exécution de l'action n'est pas transparente de manière référentielle, car l'exécution de la même action à deux reprises peut produire des résultats différents selon ce que le moteur d'exécution obtient en entrée.Grâce au système de types de Haskell, une action ne peut jamais être utilisée dans un contexte où un autre type est attendu, et inversement. Donc, si vous voulez trouver la longueur d'une chaîne, vous pouvez utiliser la
length
fonction:retournera 5. Mais si vous voulez trouver la longueur d'une chaîne lue depuis le terminal, vous ne pouvez pas écrire
parce que vous obtenez une erreur de type:
length
attend une entrée de type list (et une chaîne est, en réalité, une liste) maisgetLine
une valeur de typeIO String
(une action). De cette manière, le système de types garantit qu'une valeur d'action telle quegetLine
(dont l'exécution est exécutée en dehors du langage principal et qui peut être transparente de manière non référentielle) ne peut pas être cachée à l'intérieur d'une valeur de type non-actionInt
.MODIFIER
Pour répondre à cette question, voici un petit programme Haskell qui lit une ligne à partir de la console et en imprime la longueur.
L'action principale consiste en deux sous-actions exécutées séquentiellement:
getline
de typeIO String
,putStrLn
de typeString -> IO ()
sur son argument.Plus précisément, la deuxième action est construite par
line
à la valeur lue par la première action,length
(calculer la longueur sous forme d'entier) puisshow
(transformer l'entier en chaîne),putStrLn
au résultat deshow
.À ce stade, la deuxième action peut être exécutée. Si vous avez tapé "Bonjour", "5" sera imprimé.
Notez que si vous obtenez une valeur d'une action en utilisant la
<-
notation, vous ne pouvez utiliser cette valeur que dans une autre action, par exemple, vous ne pouvez pas écrire:car
show (length line)
a le typeString
alors que la notation do nécessite qu'une action (getLine
de typeIO String
) soit suivie d'une autre action (par exempleputStrLn (show (length line))
de typeIO ()
).EDIT 2
La définition de la transparence référentielle de Jörg W Mittag est plus générale que la mienne (j'ai voté pour sa réponse). J'ai utilisé une définition restreinte parce que l'exemple de la question porte sur la valeur de retour des fonctions et je voulais illustrer cet aspect. Cependant, RT fait généralement référence à la signification de l'ensemble du programme, y compris les changements d'état global et les interactions avec l'environnement (IO) provoqués par l'évaluation d'une expression. Donc, pour une définition correcte et générale, vous devriez vous référer à cette réponse.
la source
IO
type Haskell assez facilement dans n'importe quelle langue avec lambdas et génériques, mais comme tout le monde peut appelerprintln
directement, la mise en œuvreIO
ne garantit pas la pureté; ce serait simplement une convention.getLine
ne pas être référentiellement transparent est incorrecte. Vous présentezgetLine
comme si elle évaluait ou réduisait à une chaîne, dont la chaîne particulière dépend de l'entrée de l'utilisateur. Ceci est une erreur.IO String
ne contient pas plus de chaîne queMaybe String
ne le fait.IO String
est une recette pour peut-être, éventuellement, obtenir une chaîne et, en tant qu’expression, aussi pure que toute autre en Haskell.Cependant, ce n'est pas ce que signifie la transparence référentielle. RT signifie que vous pouvez remplacer n’importe quelle expression dans le programme par le résultat de l’évaluation de cette expression (ou inversement) sans modifier la signification du programme.
Prenons, par exemple, le programme suivant:
Ce programme est référentiellement transparent. Je peux remplacer une ou les deux occurrences de
f()
avec2
et cela fonctionnera toujours de la même manière:ou
ou
se comportera tous de la même manière.
En fait, j'ai triché. Je devrais être capable de remplacer l'appel à
print
avec sa valeur de retour (qui n'est aucune valeur) sans changer la signification du programme. Cependant, il est clair que si je supprime simplement les deuxprint
déclarations, la signification du programme changera: auparavant, il imprimait quelque chose à l'écran, après cela, pas du tout. Les E / S ne sont pas référentiellement transparentes.La règle de base est la suivante: si vous pouvez remplacer une expression, une sous-expression ou un appel de sous-routine par la valeur de retour de cette expression, sous-expression ou appel de sous-routine n’importe où dans le programme, sans que le programme en change le sens, vous avez alors un référentiel. transparence. Et ce que cela signifie, pratiquement, c'est que vous ne pouvez avoir aucun I / O, aucun état mutable, aucun effet secondaire. Dans chaque expression, la valeur de l'expression doit dépendre uniquement des valeurs des parties constitutives de l'expression. Et dans chaque appel de sous-routine, la valeur de retour doit dépendre uniquement des arguments.
la source
print
exemple. Une façon de voir cela est peut-être que ce qui est imprimé à l'écran fait partie de la "valeur de retour". Si vous pouvez remplacerprint
par la valeur de retour de la fonction et l’écriture équivalente sur le terminal, l’exemple fonctionne.4
et2 + 2
non interchangeable, car ils ont des temps d'exécution différents, et le point essentiel de la transparence référentielle est que vous pouvez remplacer une expression par ce qu'elle évalue. La considération importante serait la sécurité du fil.listOfSequence.append(n)
retourneNone
, vous devriez donc pouvoir remplacer chaque appellistOfSequence.append(n)
parNone
sans changer le sens de votre programme. Peux-tu faire ça? Si ce n'est pas le cas, alors ce n'est pas transparent par référence.Certaines parties de cette réponse proviennent directement d’un tutoriel inachevé sur la programmation fonctionnelle , hébergé sur mon compte GitHub:
Prenons un exemple simple:
Dans un langage purement fonctionnel, les côtés gauche et droit du signe égal sont substituables l'un à l'autre. C'est-à-dire que, contrairement à un langage comme C, la notation ci-dessus affirme véritablement une égalité. Une conséquence de ceci est que nous pouvons raisonner à propos du code de programme, tout comme les équations mathématiques.
De Wiki Haskell :
À l'opposé, le type d'opération exécuté par les langages de type C est parfois appelé une affectation destructive .
Le terme pur est souvent utilisé pour décrire une propriété d'expressions pertinente pour la discussion. Pour qu'une fonction soit considérée pure,
Selon la métaphore de la boîte noire, que l'on retrouve dans de nombreux manuels de mathématiques, les fonctions internes d'une fonction sont complètement isolées du monde extérieur. Un effet secondaire survient lorsqu'une fonction ou une expression enfreint ce principe. En d'autres termes, la procédure est autorisée à communiquer d'une manière ou d'une autre avec d'autres unités de programme (par exemple, pour partager et échanger des informations).
En résumé, la transparence référentielle est indispensable pour que les fonctions se comportent comme de vraies fonctions mathématiques, y compris dans la sémantique des langages de programmation.
la source
[here](link to source)
..." suivie de 2) le formatage approprié des guillemets (utilisez les guillemets, ou mieux encore, le>
symbole correspondant). Il ne serait pas aussi mal si en plus de donner des directives générales, les adresses de réponse question concrète posé des questions sur, dans ce cas à propos def(x)+f(x)
/2*f(x)
, voir Comment répondre - sinon il peut ressembler à vous simplement la publicité de votre page