Co to jest przejrzystość referencyjna?

285

Co oznacza termin przejrzystość referencyjna ? Słyszałem, że opisano to jako „oznacza to, że możesz zastąpić równe równym”, ale wydaje się to niewłaściwym wyjaśnieniem.

Claudiu
źródło
1
wow, zastanawiam się, dlaczego nagły wzrost popularności tego pytania ...
Claudiu
1
@claudia: Nie mogę powiedzieć na pewno, ale r / haskell nabrało wiatru i wielu uważało, że Uday był, choć dość dokładny, trochę szarpiąc społeczność.
efrey
6
@efrey A jibe, być może było. Ale kiedy programiści funkcjonalni zastrzelą imperatywne języki programowania i uboczne języki funkcjonalne (takie jak Lisp i ML), twierdząc, że nie są referencyjnie przejrzyste, to czy nie biorą szoku? Czy nie powinni przynajmniej właściwie ustalić swoich faktów?
Uday Reddy,
2
@Claudiu Zamieszczam go na Haskell Reddit, a Conal opublikował go na Twitterze. Uważam tę dyskusję za interesującą i uważam, że zasługuje ona na szerszą dyskusję. Zwróciłem uwagę na jibe Udaya, aby pobudzić dyskusję. Zgadzam się, że my, FPers, możemy czasem popaść w samozadowolenie i potrzebować dobrego produktu - dobrze zrobionego Udayowi za to!
chrisdornan
7
@efrey. Rzeczywiście dlatego zdecydowałem się zacytować w Bird and Wadler (semantycy?) W moim drugim poście. Osoby posiadające wiedzę wiedzą, że popularna koncepcja przejrzystości referencyjnej jest niejasna i być może niespójna. Ale nigdy nie zostało to właściwie wyjaśnione społeczności programistów. Mam nadzieję, że moje pisanie zrobi różnicę.
Uday Reddy,

Odpowiedzi:

362

Termin „przejrzystość referencyjna” pochodzi od filozofii analitycznej , gałęzi filozofii, która analizuje konstrukcje języka naturalnego, stwierdzenia i argumenty oparte na metodach logiki i matematyki. Innymi słowy, jest to najbliższy przedmiot poza informatyką, który nazywamy semantyką języka programowania . Filozof Willard Quine był odpowiedzialny za zainicjowanie koncepcji przejrzystości referencyjnej, ale był także dorozumiany w podejściach Bertranda Russella i Alfreda Whitehead.

U ich podstaw „przejrzystość referencyjna” jest bardzo prostym i jasnym pomysłem. Termin „odniesienie” jest używany w filozofii analitycznej do mówienia o rzeczy, do której odnosi się wyrażenie . Jest to mniej więcej to samo, co rozumiemy przez „znaczenie” lub „denotację” w semantyce języka programowania. Na przykładzie Andrew Birkett ( post na blogu ) termin „stolica Szkocji” odnosi się do Edynburga. To prosty przykład „odniesienia”.

Kontekst w zdaniu jest „referencyjnie przejrzysty”, jeśli zastąpienie terminu w tym kontekście innym terminem odnoszącym się do tego samego bytu nie zmienia znaczenia. Na przykład

Parlament szkocki spotyka się w stolicy Szkocji.

oznacza to samo co

Parlament szkocki spotyka się w Edynburgu.

Zatem kontekst „Parlament szkocki spotyka się w ...” jest kontekstem przejrzystym pod względem referencyjnym. Możemy zastąpić „stolicę Szkocji” „Edynburgiem” bez zmiany znaczenia. Innymi słowy, kontekst dba tylko o to, do czego odnosi się ten termin i nic więcej. W tym kontekście kontekst jest „referencyjnie przejrzysty”.

Z drugiej strony w zdaniu

Edynburg jest stolicą Szkocji od 1999 roku.

nie możemy zrobić takiej wymiany. Gdybyśmy to zrobili, otrzymalibyśmy „Edynburg był Edynburgiem od 1999 r.”, Co jest szaloną rzeczą do powiedzenia i nie ma takiego samego znaczenia jak oryginalne zdanie. Wydaje się więc, że kontekst „Edynburg był… od 1999 r.” Jest referencyjnie nieprzejrzysty (odwrotnie niż referencyjnie przejrzysty). Najwyraźniej zależy mu na czymś więcej niż to, o czym mówi ten termin. Co to jest?

Rzeczy takie jak „stolica Szkocji” nazywane są definitywnymi terminami i przez długi czas nie sprawiały kłopotów logistom i filozofom. Russell i Quine uporządkowali je, mówiąc, że tak naprawdę nie są „referencyjne”, tzn. Błędem jest myśleć, że powyższe przykłady są używane w odniesieniu do bytów. Właściwy sposób na zrozumienie „Edynburg jest stolicą Szkocji od 1999 roku” to powiedzieć

Szkocja ma stolicę od 1999 roku, a stolicą jest Edynburg.

To zdanie nie może zostać przekształcone w orzechowe. Problem rozwiązany! Celem Quine było stwierdzenie, że język naturalny jest niechlujny, a przynajmniej skomplikowany, ponieważ jest wygodny w praktycznym użyciu, ale filozofowie i logicy powinni zapewnić jasność, rozumiejąc je we właściwy sposób. Referencyjna przejrzystość jest narzędziem, które można wykorzystać do uzyskania takiej przejrzystości znaczenia .

Co to wszystko ma wspólnego z programowaniem? Właściwie nie bardzo. Jak powiedzieliśmy, przejrzystość referencyjna jest narzędziem, które można wykorzystać w zrozumieniu języka, tj. W przypisywaniu znaczenia . Christopher Strachey , który założył dziedzinę programowania języka, wykorzystał ją w swoich badaniach znaczenia. Jego podstawowy artykuł „ Podstawowe pojęcia w językach programowania ” jest dostępny w Internecie. To piękny papier i każdy może go przeczytać i zrozumieć. Więc proszę, zrób to. Będziecie znacznie oświeceni. Wprowadza termin „przejrzystość referencyjna” w tym akapicie:

Jedną z najbardziej użytecznych właściwości wyrażeń jest ta, którą wywołuje przezroczystość referencyjna Quine. Zasadniczo oznacza to, że jeśli chcemy znaleźć wartość wyrażenia zawierającego podwyrażenie, jedyne, co musimy wiedzieć o podwyrażeniu, to jego wartość. Wszelkie inne cechy wyrażenia podrzędnego, takie jak jego struktura wewnętrzna, liczba i charakter jego składników, kolejność ich oceny lub kolor tuszu, w którym są napisane, nie mają znaczenia dla wartości głównego wyrażenie.

Użycie słowa „w istocie” sugeruje, że Strachey parafrazuje go, aby wyjaśnić to w prosty sposób. Funkcjonalni programiści zdają się rozumieć ten akapit na swój własny sposób. W artykule jest 9 innych przypadków „referencyjnej przejrzystości”, ale wydaje się, że nie zawracają sobie głowy żadnym z pozostałych. W rzeczywistości cała praca Strachey poświęcona jest wyjaśnieniu znaczenia imperatywnych języków programowania . Ale dzisiaj programiści funkcjonalni twierdzą, że imperatywne języki programowania nie są względnie przejrzyste. Strachey odwróciłby się w grobie.

Możemy uratować sytuację. Powiedzieliśmy, że język naturalny jest „niechlujny, a przynajmniej skomplikowany”, ponieważ jest wygodny w praktycznym użyciu. Języki programowania są takie same. Są „niechlujne lub przynajmniej skomplikowane”, ponieważ zostały stworzone z myślą o praktyczności. To nie znaczy, że muszą nas mylić. Należy je po prostu zrozumieć we właściwy sposób, używając meta-języku, który jest referencyjnie przejrzysty, abyśmy mieli jasność znaczenia. W cytowanym przeze mnie artykule Strachey właśnie to robi. Wyjaśnia znaczenie imperatywnych języków programowania, dzieląc je na podstawowe pojęcia, nigdy nie tracąc przejrzystości. Ważną częścią jego analizy jest wskazanie, że wyrażenia w językach programowania mają dwa rodzaje „wartości”,wartości r . Przed pismem Stracheya nie zostało to zrozumiane, a zamieszanie zapanowało nadrzędnie. Dzisiaj definicja C wspomina o tym rutynowo i każdy programista C rozumie to rozróżnienie. (Trudno powiedzieć, czy programiści w innych językach rozumieją to równie dobrze).

Zarówno Quine, jak i Strachey zajmowali się znaczeniem konstrukcji językowych, które wymagają pewnej formy zależności od kontekstu. Na przykład nasz przykład „Edynburg jest stolicą Szkocji od 1999 r.” Oznacza fakt, że „stolica Szkocji” zależy od czasu, w którym jest rozpatrywana. Taka zależność od kontekstu jest rzeczywistością, zarówno w językach naturalnych, jak i językach programowania. Nawet w programowaniu funkcjonalnym zmienne swobodne i powiązane należy interpretować w odniesieniu do kontekstu, w którym się pojawiają. Zależność kontekstowa dowolnego rodzaju blokuje w pewien sposób przezroczystość referencyjną. Jeśli spróbujesz zrozumieć znaczenie terminów bez względu na kontekst, od którego są zależne, znów wpadniesz w zamieszanie. Quine zajmował się logiką modalną. Trzymał tologika modalna była referencyjnie nieprzezroczysta i powinna zostać oczyszczona poprzez przełożenie jej na referencyjnie przejrzyste ramy (np. przez uznanie konieczności za sprawdzalną). W dużej mierze przegrał tę debatę. Logicy i filozofowie uznali, że możliwa semantyka świata Kripke jest całkowicie wystarczająca. Podobna sytuacja panuje również przy programowaniu imperatywnym. Zależność od państwa wyjaśniona przez Stracheya i zależność od sklepu wyjaśniona przez Reynoldsa (w sposób podobny do możliwej semantyki świata Kripkego) są całkowicie wystarczające. Funkcjonalni programiści niewiele wiedzą o tych badaniach. Ich pomysły dotyczące przejrzystości referencyjnej należy przyjmować z dużym ziarnem soli.

[Uwaga dodatkowa: powyższe przykłady pokazują, że proste wyrażenie, takie jak „stolica Szkocji”, ma wiele poziomów znaczenia. Na pewnym poziomie możemy mówić o stolicy w obecnym czasie. Na innym poziomie moglibyśmy mówić o wszystkich możliwych stolicach, które Szkocja mogła mieć z biegiem czasu. Możemy „przybliżyć” do określonego kontekstu i „oddalić”, aby dość łatwo objąć wszystkie konteksty w normalnej praktyce. Efektywność języka naturalnego wykorzystuje naszą zdolność do tego. Imperatywne języki programowania są wydajne w bardzo podobny sposób. Możemy użyć zmiennej x po prawej stronie przypisania (wartość r ), aby mówić o jej wartości w określonym stanie. Lub możemy porozmawiać o jego wartości lktóry obejmuje wszystkie stany. Ludzie rzadko są zdezorientowani takimi rzeczami. Mogą jednak, ale nie muszą, być w stanie precyzyjnie wyjaśnić wszystkie warstwy znaczeń właściwe dla konstrukcji językowych. Wszystkie takie warstwy znaczeń niekoniecznie są „oczywiste”, a ich prawidłowe zbadanie jest kwestią nauki. Jednak brak umiejętności zwykłych ludzi do wyjaśniania takich warstwowych znaczeń nie oznacza, że ​​są zdezorientowani].

Osobny „postscriptum” poniżej wiąże tę dyskusję z obawami dotyczącymi programowania funkcjonalnego i imperatywnego .

Uday Reddy
źródło
10
Dzięki, ale nie uważam, że istnieje „oczywiste” ekstensywne pojęcie równości. Kiedy powiedziałem, że „stolica Szkocji” odnosi się do Edynburga, nie zastanawiałeś się nad tym dwa razy. Ale kiedy zacząłem mówić o „od 1999 roku”, nagle zdałeś sobie sprawę, że jest w to czas. Tak więc ekstensywne pojęcie równości może być dość subtelne i jest sformalizowane przez badaczy języka programowania. Ludzie, którzy chcą doskonale zrozumieć ekstensywną równość, muszą poznać owoce tych badań. To wcale nie musi być „oczywiste”.
Uday Reddy,
5
Fantastyczny! Mile widziana ulga od popularnych nieporozumień na temat RT, np. Powiązanie jej z funkcjami . Lub definiowanie poprzez zastąpienie wyrażenia jego wartością (jak w Wikipedii) - dziwnie, ponieważ wyrażenia i wartości są różnymi rodzajami rzeczy. Być może jednym z miejsc, w których ludzie mylą się przy rozważaniu znaczenia języków imperatywnych, jest założenie, że te „wartości” są prostymi rzeczami, takimi jak liczby, a nie bardziej złożonymi, takimi jak funkcje ze sklepu.
Conal
13
@sclv Jeśli chodzi o szerszy wpływ filozofii analitycznej na informatykę, powinienem powiedzieć, że informatyka, jak ją znamy, została założona przez Godela, Churcha, Kleene i Turinga. Ci ludzie byli logikami i dobrze znali matematyczne i filozoficzne aspekty logiki, w szczególności tradycje Peano, Frege, Russell, Whitehead, Carnap i Quine. Pierwsi pionierzy współczesnej informatyki znali powiązania. Ale szybki rozwój informatyki przerwał je. Musimy do nich wrócić.
Uday Reddy,
5
@sclv Logika jest tradycyjnie interpretowana jako nauka konsekwencji . Ale myślę, że jest szerszy. To jest nauka informacji . Quine, widzę jako pierwszy, który przedstawił szerszy pogląd. „Słowo i przedmiot” to analiza zawartości informacyjnej wypowiedzi w języku naturalnym. Jednak ani filozofowie, ani matematycy nigdy nie interesowali się obliczeniami , co jest dość kłopotliwe, biorąc pod uwagę, jak ważne były obliczenia dla cywilizacji i nauki od niepamiętnych czasów. Musimy znaleźć sposoby, aby zainteresować ich.
Uday Reddy,
3
@Conal: Dodałem nową odpowiedź, która wzmacnia twój punkt widzenia. Prawdopodobnie będzie na dole strony.
Uday Reddy,
134

Przezroczystość referencyjna, termin powszechnie używany w programowaniu funkcjonalnym, oznacza, że ​​biorąc pod uwagę funkcję i wartość wejściową, zawsze otrzymasz ten sam wynik. To znaczy, że w funkcji nie jest używany stan zewnętrzny.

Oto przykład referencyjnej przezroczystej funkcji:

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

Dzięki referencyjnej przezroczystej funkcji, podanej wartości wejściowej i funkcji, możesz zastąpić ją wartością zamiast wywoływać funkcję. Zamiast więc wywoływać plusOne z parametrem 5, moglibyśmy po prostu zastąpić to 6.

Innym dobrym przykładem jest ogólnie matematyka. W matematyce z podaną funkcją i wartością wejściową zawsze będzie odwzorowywana na tę samą wartość wyjściową. f (x) = x + 1. Dlatego funkcje w matematyce są referencyjnie przezroczyste.

Ta koncepcja jest ważna dla badaczy, ponieważ oznacza, że ​​gdy masz referencyjnie przejrzystą funkcję, nadaje się do łatwej automatycznej równoległości i buforowania.

Przezroczystość referencyjna jest zawsze używana w językach funkcjonalnych, takich jak Haskell.

-

W przeciwieństwie do tego istnieje pojęcie referencyjnej nieprzezroczystości. Oznacza to odwrotnie. Wywołanie funkcji może nie zawsze dawać taki sam wynik.

//global G
int G = 10;

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

Innym przykładem jest funkcja członka w zorientowanym obiektowo języku programowania. Funkcje składowe zwykle działają na zmiennych składowych, dlatego też byłyby referencyjne nieprzezroczyste. Funkcje członka mogą oczywiście być referencyjnie przejrzyste.

Jeszcze innym przykładem jest funkcja, która czyta z pliku tekstowego i drukuje dane wyjściowe. Ten zewnętrzny plik tekstowy może się zmienić w dowolnym momencie, więc funkcja będzie referencyjnie nieprzezroczysta.

Brian R. Bondy
źródło
1
Tylko jedna głowa w górę, możliwe jest posiadanie w pełni referencyjnie przezroczystego obiektu z referencyjnie przezroczystymi funkcjami elementu. Zobacz okmij.org/ftp/Scheme/oop-in-fp.txt
Jonathan Arkell
1
A oto kod, o którym mowa w tym artykule: okmij.org/ftp/Scheme/pure-oo-system.scm
Jonathan Arkell,
W przypadku całkowicie referencyjnie przezroczystej klasy prawdopodobnie wszystkie funkcje składowe byłyby statyczne.
Brian R. Bondy
13
To, o czym tu mówisz, nie jest przejrzystością referencyjną, choć jest powszechnie określane jako takie. Zobacz dwie odpowiedzi Uday i komentarze na ich temat. W szczególności to, co nazywacie „wyjściem”, nie jest denotacją. Jeśli zastąpisz „plusG 3” jakimkolwiek innym wyrażeniem mającym tę samą wartość / denotację, rzeczywiście otrzymasz program o tym samym znaczeniu, więc RT zachowuje ważność w imperatywnych językach. Wyrażenie „3 + 10” lub „13” nie mają tego samego znaczenia, co „plusG 3”, ponieważ znaczenie w imperatywnych językach jest funkcją „sklepu” (stanu).
Conal
1
Właśnie przeczytałem artykuł o skutkach ubocznych i zmianie stanu i mam intuicję, że ma to coś wspólnego z RT. Czy możesz dodać notatkę?
Gaurav,
91

Referencyjnie przezroczysta funkcja to taka, która zależy tylko od jej danych wejściowych.

Draemon
źródło
4
Dlatego trudno jest programować OO, ponieważ obiekty mają stan.
Kris,
5
Czy zatem słuszne jest stwierdzenie, że „referencyjnie przejrzysty” jest identyczny z „deterministycznym” podczas opisywania funkcji? Jeśli nie, jaka jest różnica między tymi dwoma terminami?
mwolfe02
1
To również brzmi jak definicja „czystej” funkcji.
Evgeny A.
75

[To jest postscriptum do mojej odpowiedzi z 25 marca, aby przybliżyć dyskusję do problemów związanych z programowaniem funkcjonalnym / imperatywnym.]

Pomysł funkcjonalnej programisty dotyczący przejrzystości odniesienia wydaje się różnić od standardowego pojęcia na trzy sposoby:

  • Podczas gdy filozofowie / logicy używają terminów takich jak „odniesienie”, „denotacja”, „desygnat” i „ bedeutung ” (niemiecki termin Frege'a ), programiści funkcjonalni używają terminu „wartość”. (Nie jest to całkowicie ich dzieło. Zauważam, że Landin, Strachey i ich potomkowie również używali terminu „wartość”, aby mówić o referencjach / denotacji. Może to być tylko terminologiczne uproszczenie, które wprowadzili Landin i Strachey, ale wydaje się, że duża różnica w przypadku naiwnego użycia).

  • Funkcjonalni programiści wydają się wierzyć, że te „wartości” istnieją w języku programowania, a nie na zewnątrz. W ten sposób różnią się zarówno od filozofów, jak i semantystów języka programowania.

  • Wydaje się, że wierzą, że te „wartości” powinny być uzyskane na podstawie oceny.

Na przykład artykuł Wikipedii na temat przejrzystości referencyjnej mówi dziś rano:

Mówi się, że wyrażenie jest względnie przezroczyste, jeśli można je zastąpić jego wartością bez zmiany zachowania programu (innymi słowy, dając program, który ma takie same efekty i dane wyjściowe na tym samym wejściu).

Jest to całkowicie sprzeczne z tym, co mówią filozofowie / logicyści. Mówią, że kontekst jest referencyjny lub referencyjnie przejrzysty, jeśli wyrażenie w tym kontekście można zastąpić innym wyrażeniem, które odnosi się do tej samej rzeczy ( wyrażenie rdzenne ). Kim są ci filozofowie / logicy? Należą do nich Frege , Russell , Whitehead , Carnap , Quine , Churchi niezliczeni inni. Każdy z nich jest niesamowitą postacią. Połączona siła intelektualna tych logików jest co najmniej wstrząsająca ziemią. Wszyscy są zgodni co do tego, że odniesienia / denotacje istnieją poza językiem formalnym, a wyrażenia w tym języku mogą tylko o nich mówić . Wszystko, co można zrobić w tym języku, to zastąpić jedno wyrażenie innym wyrażeniem, które odnosi się do tego samego bytu. Same odnośniki / oznaczenia nie istnieją w języku. Dlaczego programiści funkcjonalni odchodzą od tej ugruntowanej tradycji?

Można przypuszczać, że semantycy języka programowania mogli ich wprowadzić w błąd. Ale nie zrobili tego.

Landin :

(a) każde wyrażenie ma zagnieżdżoną strukturę podwyrażenia, (b) każde podwyrażenie oznacza coś (zwykle liczbę, wartość prawdy lub funkcję numeryczną) , (c) rzecz, którą oznacza wyrażenie, tj. jej „wartość”, zależy tylko od wartości jego podwyrażeń, a nie innych ich właściwości. [Dodano nacisk]

Stoy :

Jedyną rzeczą, która ma znaczenie dla wyrażenia, jest jego wartość, a każde podwyrażenie można zastąpić dowolną inną równą wartością [Dodatkowe wyróżnienie]. Ponadto wartość wyrażenia jest, w pewnych granicach, taka sama, ilekroć występuje ”.

Bird and Wadler :

wartość wyrażenia zależy tylko od wartości jego wyrażeń składowych (jeśli istnieją) i te podwyrażenia mogą być dowolnie zastępowane przez inne osoby o tej samej wartości [Dodatkowe wyróżnienie].

Z perspektywy czasu wysiłki Landina i Stracheya mające na celu uproszczenie terminologii poprzez zastąpienie „odniesienia” / „denotacji” „wartością” mogły być nieuzasadnione. Gdy tylko usłyszy się o „wartości”, pojawia się pokusa, aby pomyśleć o procesie oceny, który do niej prowadzi. Równie kuszące jest myślenie o tym, co powstaje w wyniku oceny, jako o „wartości”, chociaż może być całkiem jasne, że to nie jest denotacja. To, co zbieram, stało się z koncepcją „przejrzystości referencyjnej” w oczach programistów funkcjonalnych. Ale „wartość”, o której mówili pierwsi semantycy, nie jest wynikiem oceny, rezultatu funkcji lub czegoś takiego. Jest to oznaczenie tego terminu.

Kiedy zrozumiemy tak zwaną „wartość” wyrażenia („odniesienie” lub „denotacja” w dyskursie filozofów klasycznych) jako złożony obiekt matematyczno-konceptualny, otwierają się wszelkie możliwości.

  • Strachey interpretował zmienne w imperatywnych językach programowania jako wartości L , jak wspomniano w mojej odpowiedzi z 25 marca, która jest wyrafinowanym obiektem koncepcyjnym, który nie ma bezpośredniej reprezentacji w składni języka programowania.
  • Interpretował także polecenia w takich językach, jak funkcje stan-stan, kolejne wystąpienie złożonego obiektu matematycznego, który nie jest „wartością” w składni.
  • Nawet wywołujące skutki uboczne wywołanie funkcji w C ma dobrze zdefiniowaną „wartość” jako transformator stanu, który odwzorowuje stany na pary stanów i wartości (tak zwana „monada” w terminologii programistów funkcjonalnych).

Niechęć programistów funkcyjnych do nazywania takich języków „referencyjnie przejrzystymi” oznacza po prostu, że niechętnie przyjmują tak złożone obiekty matematyczne / koncepcyjne jako „wartości”. Z drugiej strony wydają się doskonale gotowi nazwać transformator stanu „wartością”, gdy jest on umieszczony w swojej ulubionej składni i ubrany w brzęczące słowo, takie jak „monada”. Muszę powiedzieć, że są one całkowicie niespójne, nawet jeśli przyznamy im, że ich idea „przejrzystości odniesienia” ma pewną spójność.

Trochę historii może rzucić nieco światła na to, jak powstały te zamieszania. Okres od 1962 do 1967 roku był bardzo intensywny dla Christophera Stracheya. W latach 1962-65 podjął pracę w niepełnym wymiarze godzin jako asystent naukowy u Maurice'a Wilkesa, aby zaprojektować i wdrożyć język programowania, który stał się znany jako CPL. Był to imperatywny język programowania, ale miał też mieć potężne możliwości funkcjonalnego języka programowania. Landin, który był pracownikiem Strachey w swojej firmie konsultingowej, miał ogromny wpływ na pogląd Stracheya na języki programowania. W przełomowym artykule z 1965 r. „ Następne 700 języków programowania ” Landin bezwstydnie promuje funkcjonalne języki programowania (nazywając je denotatywnymi)języki) i opisuje imperatywne języki programowania jako „antytezę”. W dalszej dyskusji Strachey wątpi w silną pozycję Landina.

... DL tworzą podzbiór wszystkich języków. To interesujący podzbiór, ale niewygodny w użyciu, chyba że jesteś do tego przyzwyczajony. Potrzebujemy ich, ponieważ w tej chwili nie wiemy, jak konstruować dowody w językach, które zawierają imperatywy i skoki. [Dodano nacisk]

W 1965 roku Strachey objął stanowisko Czytelnika w Oksfordzie i wydaje się, że pracował w pełnym wymiarze godzin nad opracowaniem teorii imperatywów i skoków. W 1967 r. Był gotowy na teorię, której nauczał na kursie „ Podstawowe pojęcia w językach programowania ” w letniej szkole w Kopenhadze. Notatki z wykładu miały zostać opublikowane, ale „niestety, z powodu opieszałej redakcji, postępowanie nigdy się nie zmaterializowało; podobnie jak większość prac Strachey w Oxfordzie, gazeta miała wpływowy prywatny obieg”. ( Martin Campbell-Kelly )

Trudność w uzyskaniu pism Stracheya mogła doprowadzić do rozpowszechnienia zamieszania, a ludzie polegali na źródłach wtórnych i pogłoskach. Ale teraz, gdy „ podstawowe pojęcia ” są łatwo dostępne w Internecie, nie ma potrzeby uciekać się do zgadywania pracy. Powinniśmy to przeczytać i zdecydować, co miał na myśli Strachey. W szczególności:

  • W sekcji 3.2 zajmuje się „wyrażeniami”, w których mówi o „przejrzystości referencyjnej wartości R”.
  • Jego sekcja 3.3 dotyczy „poleceń”, w których mówi o „przezroczystości referencyjnej wartości L”.
  • W sekcji 3.4.5 mówi o „funkcjach i procedurach” i oświadcza, że ​​„wszelkie odstępstwa od przezroczystości referencyjnej wartości R w kontekście wartości R należy albo wyeliminować, rozkładając wyrażenie na kilka poleceń i prostsze wyrażenia, albo, jeśli okazuje się to trudne, temat komentarza ”.

Mówienie o „referencyjnej przezroczystości” bez zrozumienia rozróżnienia między wartościami L, wartościami R i innymi złożonymi obiektami, które zaludniają wszechświat konceptualny programisty, jest zasadniczo błędne.

Uday Reddy
źródło
10
Myślę, że warto podkreślić, że pomieszanie tych dwóch pojęć „wartości” (oceny vs denotacje) wprowadza w błąd programistów funkcjonalnych w ich krytyce języków imperatywnych , w których różnica między pojęciami jest duża.
Conal,
8
tzn. pojęcie oceny prowadzi do wniosku, że imperatywnymi językami nie są RT, podczas gdy pojęcie denotacji nie.
Conal,
12
Wydaje mi się, że kiedy naprawdę w pełni opanujesz denotacyjną semantykę języka, nie może to pozostać przejrzyste. Wydaje się to zatem równoznaczne z powiedzeniem, że termin ten nie jest użyteczny w odniesieniu do języków programowania.
Tom Crockett,
20
Wygląda więc na to, że ludzie używają tego terminu, aby oznaczać coś istotnie innego niż to, co inni ludzie mieli na myśli, gdy używali tego terminu w przeszłości. Do czego mówię: Witamy w języku angielskim.
Daniel Pratt
17
@DanielPratt: Jeśli to, co chcą funkcjonalni programiści, oznacza wolność od skutków ubocznych, to dlaczego nazywają to „przejrzystością referencyjną”? Mogą to po prostu nazwać „swobodą efektów ubocznych”, co jest ideą całkowicie jasną. Nikt nie będzie musiał pytać przy zmianie stosu, co oznacza „wolność od efektów ubocznych”. Gdzie jest potrzeba kradzieży wspaniałych klasycznych terminów, których nikt nie rozumie?
Uday Reddy
23

Wyrażenie jest referencyjnie przezroczyste, jeśli można je zastąpić jego wartością bez zmiany algorytmu, uzyskując algorytm, który ma takie same efekty i dane wyjściowe na tych samych danych wejściowych.

CMS
źródło
18

Referencyjnie przejrzysta funkcja to taka, która działa jak funkcja matematyczna; przy tych samych danych wejściowych zawsze będzie generować te same dane wyjściowe. Oznacza to, że przekazany stan nie jest modyfikowany i że funkcja nie ma własnego stanu.

Barry Kelly
źródło
10

Dla tych, którzy potrzebują zwięzłego wyjaśnienia, zaryzykuję jedno (ale przeczytaj poniższe ujawnienie).

Przezroczystość referencyjna w języku programowania promuje rozumowanie z równań - im większa jest przejrzystość z odniesieniami, tym łatwiej jest robić rozumowanie z równań. Np. Z definicją funkcji (pseudo)

fx = x + x,

łatwość, z jaką można (bezpiecznie) zamienić f (foo) na foo + foo w zakresie tej definicji, bez zbyt wielu ograniczeń co do miejsca, w którym można wykonać tę redukcję, jest dobrym wskaźnikiem tego, ile przejrzystości referencyjnej ma język programowania ma.

Na przykład, jeśli foo to x ++ w sensie programowania C, to nie można bezpiecznie wykonać tej redukcji (to znaczy, jeśli wykonując tę ​​redukcję, nie uzyskałbyś tego samego programu, z którym zacząłeś).

W praktycznych językach programowania nie zobaczysz doskonałej przejrzystości referencyjnej, ale funkcjonalnym programistom zależy na tym bardziej niż większości (por. Haskell, gdzie jest to główny cel).

(Pełne ujawnienie: Jestem programistą funkcjonalnym, więc przy pierwszej odpowiedzi powinieneś wziąć to wyjaśnienie z odrobiną soli.)

chrisdornan
źródło
3
Nie mam problemu z językami ułatwiającymi rozumowanie równe. Chciałbym jednak zakwestionować fakt, że ma to coś wspólnego z „przejrzystością referencyjną” zgodnie z klasyczną definicją. Po drugie, jako praktyczny programista uważam, że rozumowanie równania jest przereklamowane. Rozumowanie, które jest ważne w praktyce, dotyczy warunków wstępnych, warunków dodatkowych, niezmienników i abstrakcji danych. Dla ludzi, którzy polegają na takich technikach rozumowania, efekty uboczne wydają się nie mieć większego znaczenia. Tak więc, chociaż zgadzam się z tobą, że skutki uboczne w wyrażeniach są złym pomysłem, nie wydają się reprezentować argumentu zabójcy.
Uday Reddy,
1
@UdayReddy Tylko dlatego, że programiści funkcjonalni wybrali określoną metodę wybierania przezroczystości referencyjnej w swoich programach (eliminacja skutków ubocznych i opracowanie wyrafinowanej i potężnej algebry programów), lub mają praktyków, którzy prawdopodobnie nie rozumieją przejrzystości referencyjnej, a także ich zdaniem tak nie jest, nie oznacza to, że funkcjonalne języki programowania nie zwiększają przejrzystości referencyjnej ani że programiści języków funkcjonalnych i autorzy kompilatorów nie wykorzystują tego wzrostu formalnej podatności na wiele dobrych celów.
chrisdornan
2
Chris: Uday wskazał, że Strachey wyeliminował problem referencyjnego krycia w semantyce języka programowania, szczególnie w przypadku języków rozkazujących. Funkcjonalni programiści nie mogą więc „wybierać przezroczystości referencyjnej w swoich programach”. Jako konkretny przykład, Haskell IO nie pomaga w RT dokładnie dlatego, że nie jest potrzebna pomoc RT.
Conal
2
@chrisdornan: Przepraszam za mój pierwszy komentarz powyżej. Sam miałem trudności z rozróżnieniem tego, co próbowałem powiedzieć w pierwszych dwóch zdaniach :-( Ale oto wyjaśnienie. Rozważmy dwupoziomowy lub wielopoziomowy rachunek różniczkowy. Każdy operator pomostowy jest referencyjnie nieprzejrzysty. W rzeczywistości jest ., operator cytat można jednak zrobić equational rozumowania w ramach każdego etapu perfekcyjnie Więc każdy operator referentially nieprzezroczysty ustawić granice dla equational rozumowania, ale wciąż masz equational rozumowanie w tych granicach...
Uday Reddy
1
@chrisdomain: Ponadto bardzo niewiele osób chciałoby być referencyjnymi purystami przejrzystości, aby wyrzucić takich operatorów inscenizacji. Ci operatorzy są niezwykle przydatni. Programowanie bez nich poprzez ręczne ustawianie byłoby uciążliwe, podatne na błędy i brzydkie. A ręczne wykonanie inscenizacji nie przyniosłoby ci więcej racjonalnego uzasadnienia niż to, co wcześniej. Tak więc zakazanie dobrych urządzeń programistycznych w purystycznym dążeniu do równego rozumowania byłoby jak odcięcie nosa na przekór twarzy.
Uday Reddy
8

Jeśli interesuje Cię etymologia (tj. Dlaczego ta koncepcja ma tę konkretną nazwę), spójrz na mój post na blogu na ten temat. Terminologia pochodzi od filozofa / logika Quine'a.

Andrew Birkett
źródło
4
  1. Semantyka denotacyjna opiera się na językach modelowania poprzez budowanie domen, które stanowią wartości możliwe do oznaczenia .
  2. Funkcjonalni programiści używają terminu wartość do opisania zbieżności obliczeń opartych na regułach przepisywania języka tj. jego semantyka operacyjna.

W 1 widać klarowność dwóch języków:

  • modelowany, język obiektowy
  • język modelowania, metajęzyk

W 2, dzięki bliskości przedmiotu i języków metalowych, można je pomylić.

Jako realizator języka uważam, że muszę stale pamiętać o tym rozróżnieniu.

Prof. Reddy, mogę sparafrazować was w ten sposób :-)

W kontekście programowania funkcjonalnego i semantyki termin Przezroczystość referencyjna nie jest referencyjnie przejrzysty.

Anuradha
źródło
1
Ha ha. Dziękuję za wyjaśnienie. Problem polega także na tym, że funkcjonalni programiści zachowują się tak, jakby mieli ogólne pojęcie „przejrzystości odniesienia”, które ma zastosowanie do wszystkich języków programowania . Zależy to jednak od ich pojęcia „wartości”, co może, ale nie musi mieć sensu dla innych języków. Aby zgłosić ogólną teorię „przejrzystości odniesienia”, muszą stworzyć ogólną teorię „wartości”. Tego dotychczas brakuje.
Uday Reddy,
4

Poniższa odpowiedź, mam nadzieję, uzupełnia i kwalifikuje kontrowersyjne odpowiedzi 1 i 3.

Przyznajmy, że wyrażenie oznacza lub odnosi się do jakiegoś odniesienia. Pytanie brzmi jednak, czy odniesienia te mogą być kodowane izomorficznie jako część samych wyrażeń, nazywając takie wyrażenia „wartościami”. Na przykład wartości liczb literalnych są podzbiorem zbioru wyrażeń arytmetycznych, wartości prawdy są podzbiorem zbioru wyrażeń boolowskich itp. Chodzi o to, aby ocenić wyrażenie na jego wartość (jeśli ma takie wyrażenie). Zatem słowo „wartość” może odnosić się do denotacji lub do wyróżnionego elementu zestawu wyrażeń. Ale jeśli istnieje izomorfizm (bijection) między odniesieniem a wartością, możemy powiedzieć, że są tym samym. (To powiedziawszy, należy uważać, aby zdefiniować odniesienia i izomorfizm, czego dowodzi pole semantyki denotacyjnej. Aby podać przykład wspomniany w odpowiedziach na trzecią odpowiedź,data Nat = Zero | Suc Nat nie odpowiada oczekiwanemu zestawowi liczb naturalnych).

Napiszmy E[·]dla wyrażenia z dziurą, znanego również w niektórych miejscach jako „kontekst”. Dwa kontekstowe przykłady wyrażeń podobnych do C to [·]+1i [·]++.

Napiszmy [[·]]dla funkcji, która przyjmuje wyrażenie (bez dziury) i podaje swoje znaczenie (odniesienie, denotacja itp.) W jakimś wszechświecie dostarczającym znaczenia. (Pożyczam notację z dziedziny semantyki denotacyjnej.)

Dostosujmy definicję Quine'a nieco formalnie w następujący sposób: kontekst E[·] jest referencyjnie przejrzysty iff, biorąc pod uwagę dowolne dwa wyrażenia E1i E2(bez dziur) taki, że [[E1]] = [[E2]](tj. Wyrażenia oznaczają / odnoszą się do tego samego odwołania) to jest tak, że [[E[E1]]] = [[E[E2]]](tj. Wypełnienie -w otworze z albo E1albo E2powoduje wyrażenie, które również oznacza to samo odniesienie).

Zasada Leibniza polegająca na zamianie równości na równość jest zwykle wyrażana jako „jeśli E1 = E2to E[E1] = E[E2]”, co E[·]oznacza, że jest to funkcja. Funkcja (lub w tym przypadku program obliczający funkcję) to mapowanie ze źródła do celu, tak że dla każdego elementu źródłowego istnieje co najwyżej jeden element docelowy. Funkcje niedeterministyczne są mylącymi nazwami, są albo relacjami, funkcjami dostarczającymi zbiory itp. Jeśli w regule Leibniza równość =jest denotacyjna, to podwójny nawias jest po prostu brany za pewnik i unika. Tak więc referencyjnie przejrzysty kontekst jest funkcją. Reguła Leibniza jest głównym składnikiem rozumowania równań, więc rozumowanie równania jest zdecydowanie powiązane z przejrzystością referencyjną.

Chociaż [[·]]jest funkcją od wyrażeń do denotacji, może być funkcją od wyrażeń do „wartości” rozumianych jako ograniczony podzbiór wyrażeń i [[·]]może być rozumiany jako ocena.

Teraz, jeśli E1jest wyrażeniem i E2wartością, mamy to, co myślę, że ma na myśli większość ludzi, definiując przejrzystość referencyjną pod względem wyrażeń, wartości i oceny. Ale jak ilustrują 1. i 3. odpowiedź na tej stronie, jest to niedokładna definicja.

Problem z kontekstami takimi jak [·]++nie jest efektem ubocznym, ale że jego wartość nie jest zdefiniowana w C izomorficznie do jego znaczenia. Funkcje nie są wartościami (no, wskaźniki do funkcji), podczas gdy w funkcjonalnych językach programowania są. Landin, Strachey i pionierzy denotacyjnej semantyki dość sprytnie używali światów funkcjonalnych do nadawania znaczenia.

W przypadku imperatywnych języków podobnych do C możemy (z grubsza) zapewnić semantykę wyrażeń za pomocą funkcji [[·]] : Expression -> (State -> State x Value).

Valuejest podzbiorem Expression. Statezawiera pary (identyfikator, wartość). Funkcja semantyczna przyjmuje wyrażenie i dostarcza jako swoje znaczenie funkcję od stanu bieżącego do pary ze stanem zaktualizowanym i wartością. Na przykład [[x]]jest funkcją od stanu bieżącego do pary, której pierwszym składnikiem jest stan bieżący, a drugim składnikiem jest wartość x. Natomiast [[x++]]jest funkcją od stanu bieżącego do pary, której pierwszym składnikiem jest stan, w którym wartość x jest zwiększana, a którego drugim składnikiem jest właśnie ta wartość. W tym sensie kontekst [·]++jest referencyjnie przejrzysty, jeżeli spełnia powyższą definicję.

Myślę, że programiści funkcjonalni mają prawo do korzystania z przezroczystości referencyjnej w tym sensie, że naturalnie odzyskują [[·]]funkcję funkcji od wyrażeń do wartości. Funkcje są pierwszorzędnymi wartościami, a stan może być również wartością, a nie denotacją. Monada stanu jest (częściowo) czystym mechanizmem przekazywania (lub tworzenia wątków) stanu.


źródło
Przypuszczalnie odpowiedzi „1” i „3” to odpowiednio odpowiedzi „25 marca” i „PostScript” UdayReddy'ego. Ordynacje nie są dobrym sposobem na odniesienie się do odpowiedzi w SO. Głosy i akceptacje mogą nie tylko zmieniać się w czasie, ale istnieje wiele możliwych do wyboru porządków.
philipxy
2

Zauważ, że ta koncepcja „znaczenia” dzieje się w umyśle obserwatora. Zatem to samo „odniesienie” może oznaczać różne rzeczy dla różnych ludzi. Na przykład w Wikipedii mamy stronę z ujednoznacznieniem w Edynburgu.

Powiązanym zagadnieniem, które może pojawić się w kontekście programowania, może być polimorfizm.

Być może powinniśmy mieć nazwę specjalnego przypadku polimorfizmu (a może nawet rzutowania), w którym dla naszych celów różne przypadki polimorficzne są semantycznie równoważne (a nie tylko podobne. Na przykład liczba 1 - która może być reprezentowana przy użyciu typu liczby całkowitej, typu złożonego lub dowolnego z wielu innych typów - można je traktować polimorficznie).

rdm
źródło
0

Uznałem, że definicja przejrzystości referencyjnej w książce „ Struktura i implementacja programów komputerowych ” (Wizard Book) jest przydatna, ponieważ uzupełnia ją wyjaśnienie, w jaki sposób naruszona została przejrzystość referencyjna poprzez wprowadzenie operacji przypisania . Sprawdź następującą zjeżdżalnię, którą zrobiłem na ten temat: https://www.slideshare.net/pjschwarz/introducing-assignment-invalidates-the-substitution-model-of-aluation-and-violates-referenceial-transparency-as- wyjaśnił-w-sicp-the-Wizard-book

Philip Schwarz
źródło
0

Przejrzystość odniesienia można po prostu określić jako:

  • Wyrażenie zawsze oceniające na ten sam wynik w dowolnym kontekście [1] ,
  • Funkcja, jeśli otrzyma dwa razy te same parametry, musi dwukrotnie dać ten sam wynik [2] .

Na przykład język programowania Haskell jest językiem czysto funkcjonalnym; co oznacza, że ​​jest referencyjnie przejrzysty.

Mogą
źródło