Czy ktoś wykorzystał polimorficzną defunkcjonalizację Pottiera i Gauthiera w kompilatorze modułowym?

15

Defunkcjonalizacja to transformacja programu, która przekształca programy wyższego rzędu w programy pierwszego rzędu. Chodzi o to, że biorąc pod uwagę program, istnieje tylko skończona liczba abstrakcji lambda, więc można zastąpić każdą lambda identyfikatorem, a każdą aplikację funkcji wywołaniem procedury wprowadzania, która rozgałęzia się na tym identyfikatorze. Jest to czasami używane w kompilatorach dla języków funkcjonalnych, ale jego zastosowanie jest ograniczone przez fakt, że defunkcjonalizacja jest transformacją całego programu (musisz statystycznie znać wszystkie funkcje w programie), dlatego tylko kompilatory całego programu korzystają z to.

Jednak Pottier i Gauthier mają określony algorytm defunkcjonalizacji o typie polimorficznym, wykorzystujący bardziej wyrafinowane typowanie z udziałem GADT. Teraz, biorąc pod uwagę ich kodowanie, możliwe jest dodanie wielkiej wielkości liter do ich typu danych lambda, który nie jest znacznikiem, ale zawiera funkcję wyższego rzędu. Oznacza to, że powinno być możliwe wykorzystanie ich kodowania do defekcjonalizacji na zasadzie moduł po module.

Czy ktoś to zrobił i wskazał mi kompilator korzystający z tego pomysłu? (Kompilatory zabawek są w porządku i faktycznie preferowane).

Neel Krishnaswami
źródło

Odpowiedzi:

6

Jedno podejście opisuje

Georgios Fourtounis i Nikolaos S. Papaspyrou. 2013. Obsługa oddzielnej kompilacji w kompilatorze z defektywalizacją. ŁUPEK 2013.

Jak wspomina @gasche:

Innym podejściem do problemu byłoby rozważenie, że każdy moduł może zdefiniować swój własny typ „funkcji funkcjonalnych” i dyspozytora / obsługi.

nja0<ja<nn-ja

Blaisorblade
źródło
4

Teraz, biorąc pod uwagę ich kodowanie, możliwe jest dodanie wielkiej wielkości liter do ich typu danych lambda, który nie jest znacznikiem, ale zawiera funkcję wyższego rzędu. Oznacza to, że powinno być możliwe wykorzystanie ich kodowania do defekcjonalizacji na zasadzie moduł po module.

Czy mógłbyś bardziej szczegółowo wyjaśnić, co masz na myśli? Nie rozumiem, w jaki sposób dodanie przypadku podstawowego (czy byłoby to w typie danych, w dopasowaniu wzorca funkcji wysyłającej, czy w obu przypadkach) pomaga modułowości w opisany sposób; a tak przy okazji, dlaczego masz na myśli dokładnie „moduł po module”?

Mogę sobie wyobrazić użycie „przypadku podstawowego” wewnątrz danego modułu / programu do selektywnej defekalizacji: miałbyś dodatkowy konstruktor dla swojego poprawionego typu funkcji, który nie jest tagiem, ale po prostu osadza wszystkie 'a -> 'bfunkcje, tak aby spakować funkcję w tym konstruktorze, zamiast nadania mu poprawionego znacznika, zapobiegałby jego defektywalizacji.

Innym podejściem do problemu byłoby rozważenie, że każdy moduł może zdefiniować swój własny typ „funkcji funkcjonalnych” i dyspozytora / obsługi. Funkcje z modułu M1miałyby typ M1.arrowi byłyby stosowane przy użyciu M1.applyitp. Chociaż działa to dobrze w przypadku korzystania z funkcji pierwszego rzędu, nie bardzo dobrze widzę, jak można rozszerzyć go na funkcję wyższego rzędu (co nie powinno być konieczne wiedzieć, skąd pochodzi ich argument funkcjonalny): jeśli połączysz funkcję z jej dyspozytorem, ponownie wejdziesz w sferę pośrednich wywołań funkcji.

Na koniec w artykule wspomniałeś o szybkim wspominaniu o podejściu całego programu vs. modułowości, ale nie rozumiem, jak odnosi się to do twojej propozycji. To, co opisują, wyraża się w kategoriach „otwartych rozszerzeń” zarówno funkcji, jak i typów danych (funkcje i typy, które można zdefiniować w kilku niezależnych modułach). Jest to głównie sposób ML na opisanie faktu, że można odroczyć połączenie analizy / transformacji niezależnych modułów w czasie łączenia, odciążając konieczność transformacji całego programu.

gasche
źródło