Chcę zrozumieć na niskim poziomie, co by się stało, gdyby struktura danych nie była trwała?
Spójrzmy na generator liczb pseudolosowych z ogromną przestrzenią stanów (jak „ twister Mersenne ” o stanie 2450 bajtów) jako strukturę danych. Tak naprawdę nie chcemy używać żadnej liczby losowej więcej niż jeden raz, więc wydaje się, że nie ma powodu, aby wdrażać ją jako niezmienną trwałą strukturę danych. Teraz zadajmy sobie pytanie, co może pójść nie tak w następującym kodzie:
mt_gen = CreateMersenneTwisterPRNGen(seed)
integral = MonteCarloIntegral_Bulk(mt_gen) + MonteCarloIntegral_Boundary(mt_gen)
Większość języków programowania nie określa kolejności MonteCarloIntegral_Bulk
i MonteCarloIntegral_Boundary
będzie oceniana. Jeśli oba przyjmą jako argument odwołanie do mutowalnego mt_gen, wynik tego obliczenia może zależeć od platformy. Co gorsza, mogą istnieć platformy, na których wynik nie jest w ogóle odtwarzalny pomiędzy różnymi przebiegami.
Można zaprojektować wydajną, zmienną strukturę danych dla mt_gen, tak aby każde przeplatanie wykonania MonteCarloIntegral_Bulk
i MonteCarloIntegral_Boundary
dawało „poprawny” wynik, ale inne przeplatanie generalnie prowadzi do innego „poprawnego” wyniku. Ta nieodtwarzalność powoduje, że odpowiednia funkcja jest „nieczysta”, a także prowadzi do innych problemów.
Niereprodukowalności można uniknąć poprzez wymuszenie stałej kolejności wykonywania sekwencyjnego. Ale w takim przypadku kod może być ustawiony w taki sposób, aby w danym momencie było dostępne tylko jedno odwołanie do mt_gen. W typowym funkcjonalnym języku programowania można zastosować typy unikatowości, aby wymusić to ograniczenie, umożliwiając w ten sposób bezpieczne modyfikowalne aktualizacje również w kontekście czysto funkcjonalnych języków programowania. Wszystko to może brzmieć ładnie i elegancko, ale przynajmniej teoretycznie symulacje Monte Carlo są żenująco równoległe, a nasze „rozwiązanie” właśnie zniszczyło tę właściwość. To nie jest tylko problem teoretyczny, ale bardzo realny problem praktyczny. Musimy jednak zmodyfikować (oferowaną przez nas funkcję) nasz generator liczb pseudolosowych i sekwencję liczb losowych, które produkuje, i żaden język programowania nie może zrobić tego automatycznie dla nas. (Oczywiście możemy użyć innej biblioteki liczb pseudolosowych, która już oferuje wymaganą funkcjonalność).
Na niskim poziomie, zmienne struktury danych łatwo prowadzą do braku powtarzalności (a zatem i zanieczyszczenia), jeśli kolejność wykonywania nie jest sekwencyjna i ustalona. Typową strategią konieczną do rozwiązania tych problemów jest sekwencyjne fazy ze stałą kolejnością wykonywania, podczas których zmieniane są zmienne struktury danych, oraz równoległe fazy z dowolną kolejnością wykonywania, podczas których wszystkie współużytkowane zmienne struktury danych pozostają stałe.
Andrej Bauer podniósł kwestię aliasingu dla zmiennych struktur danych. Co ciekawe, różne imperatywne języki, takie jak Fortran i C, mają różne założenia dotyczące dozwolonego aliasingu argumentów funkcji, a większość programistów jest zupełnie nieświadoma, że ich język ma w ogóle model aliasingu.
Niezmienność i semantyka wartości mogą być nieco przereklamowane. Co ważniejsze, system typów i struktura logiczna (jak abstrakcyjny model maszyny, model aliasingu, model współbieżności lub model zarządzania pamięcią) twojego języka programowania zapewniają wystarczające wsparcie dla „bezpiecznej” pracy z „wydajnymi” danymi Struktury. Wprowadzenie „semantyki ruchu” do C ++ 11 może wyglądać jak ogromny krok wstecz pod względem czystości i „bezpieczeństwa” z teoretycznego punktu widzenia, ale w praktyce jest odwrotnie. System typów i logiczna struktura języka zostały rozszerzone, aby usunąć ogromne części niebezpieczeństwa związanego z nową semantyką. (I nawet jeśli pozostaną ostre krawędzie, nie oznacza to, że nie można tego poprawić „lepszym”
Uday Reddy podniósł kwestię, że matematyka nigdy nie działała ze zmiennymi obiektami danych oraz że systemy typów programów funkcjonalnych są dobrze opracowane dla niezmiennych obiektów danych. Przypomniało mi to wyjaśnienie Jean-Yvesa Girarda, że matematyka nie jest wykorzystywana do pracy ze zmiennymi obiektami, kiedy próbuje motywować logikę liniową.
Można zapytać, jak rozszerzyć system typów i strukturę logiczną funkcjonalnych języków programowania, aby umożliwić „bezpieczną” pracę z „wydajnymi”, zmiennymi, nietrwałymi strukturami danych. Jednym z problemów może być to, że klasyczne logiki i algebry logiczne mogą nie być najlepszym logicznym szkieletem do pracy ze zmiennymi strukturami danych. Być może logika liniowa i monoidy przemienne mogą być lepiej dostosowane do tego zadania? Być może powinienem przeczytać, co Philip Wadler ma do powiedzenia na temat logiki liniowej jako systemu pisma dla funkcjonalnych języków programowania? Ale nawet jeśli logika liniowa nie byłaby w stanie rozwiązać tego problemu, nie oznacza to, że system typów i struktura logiczna funkcjonalnego języka programowania nie mogą zostać rozszerzone, aby umożliwić „bezpieczne” i „wydajne”