Problem reprezentowania zmiennych powiązanych w składni, a zwłaszcza podstawiania unikania przechwytywania, jest dobrze znany i ma wiele rozwiązań: zmienne nazwane z równoważnością alfa, wskaźniki de Bruijna, lokalna bezimienność, zbiory nominalne itp.
Ale wydaje się, że istnieje inne dość oczywiste podejście, którego jednak nigdzie nie widziałem. Mianowicie, w podstawowej składni mamy tylko jeden termin „zmienny”, zapisany powiedzmy , a następnie osobno dajemy funkcję, która mapuje każdą zmienną na spoiwo, w którego zakresie się ona znajduje. Tak jak termin λ
zostanie napisane , a funkcja odwzorowuje pierwszą ∙ na pierwszą λ, a drugą ∙ na drugą λ . Jest to więc coś w rodzaju wskaźników de Bruijna, tylko zamiast „liczyć λs ”, gdy wycofujesz się z terminu, aby znaleźć odpowiednie spoiwo, po prostu oceniasz funkcję. (Reprezentując to jako strukturę danych w implementacji, pomyślałbym o wyposażeniu każdego obiektu o zmiennej wartości w prosty wskaźnik / odniesienie do odpowiedniego obiektu o charakterze wiążącym).
Oczywiście nie jest to rozsądne, aby pisać składnię na stronie, aby ludzie mogli ją przeczytać, ale wtedy też nie są to wskaźniki de Bruijna. Wydaje mi się, że ma to matematyczny sens, w szczególności sprawia, że bardzo łatwo jest zastąpić unikanie przechwytywania: wystarczy wpisać termin, który zastępujesz i wziąć połączenie funkcji wiążących. To prawda, że nie ma pojęcia „zmiennej zmiennej”, ale (ponownie) tak naprawdę nie ma też indeksów de Bruijna; w obu przypadkach termin zawierający wolne zmienne jest reprezentowany z przodu z listą segregatorów „kontekstowych”.
Czy coś mi brakuje i jest jakiś powód, dla którego ta reprezentacja nie działa? Czy są problemy, które sprawiają, że jest o wiele gorzej niż inne, że nie warto brać pod uwagę? (Jedyny problem, jaki mogę teraz wymyślić, to to, że zestaw terminów (wraz z ich wiążącymi funkcjami) nie jest zdefiniowany indukcyjnie, ale nie wydaje się to nie do pokonania.) Czy są też miejsca, w których zostały użyte?
źródło
Odpowiedzi:
Odpowiedzi Andreja i Łukasza są dobre, ale chciałem dodać dodatkowe komentarze.
Aby powtórzyć to, co powiedział Damiano, ten sposób przedstawiania wiązania za pomocą wskaźników jest tym, który sugerują siatki próbne, ale najwcześniejsze miejsce, w którym widziałem go dla wyrażeń lambda, było w starym eseju Knutha:
Na stronie 234 narysował następujący schemat (który nazwał „strukturą informacji”) reprezentującą termin :(λy.λz.yz)x
Ten rodzaj graficznej reprezentacji terminów lambda był również badany niezależnie (i głębiej) w dwóch tezach na początku lat siedemdziesiątych, zarówno przez Christophera Wadswortha (1971, Semantics and Pragmatics of the Lambda-Calculus ), jak i Richarda Statmana (1974, Structural Complexity dowodów ). Obecnie takie diagramy są często nazywane „wykresami λ” (patrz na przykład ten artykuł ).
Zauważ, że termin na diagramie Knutha jest liniowy , w tym sensie, że każda wolna lub związana zmienna występuje dokładnie jeden raz - jak wspomnieli inni, istnieją nietrywialne problemy i wybory, które należy podjąć, próbując rozszerzyć tego rodzaju reprezentację na nie warunki liniowe.
Z drugiej strony, jeśli chodzi o warunki liniowe, myślę, że to świetnie! Liniowość wyklucza potrzebę kopiowania, więc otrzymujesz zarówno równoważność jak i podstawienie „za darmo”. Są to te same zalety, co HOAS, i faktycznie zgadzam się z Rodolphe Lepigre, że istnieje związek (jeśli nie dokładnie równoważność) między dwiema formami reprezentacji: istnieje poczucie, że te struktury graficzne mogą być naturalnie interpretowane jako diagramy ciągów , reprezentujących endomorfizmy obiektu zwrotnego w zwartej zamkniętej dwukategorii (podałem krótkie wyjaśnienie tegoα tutaj ).
źródło
Nie jestem pewien, w jaki sposób twoja funkcja zmiennej do spoiwa byłaby reprezentowana i do jakiego celu chcesz jej użyć. Jeśli używasz wskaźników wstecznych, to jak zauważył Andrej, złożoność obliczeniowa podstawienia nie jest lepsza niż klasyczna zmiana nazw alfa.
Z twojego komentarza do odpowiedzi Andreja wnioskuję, że do pewnego stopnia jesteś zainteresowany dzieleniem się. Mogę tu podać jakieś informacje.
W typowym typowym rachunku lambda osłabienie i skurcz, w przeciwieństwie do innych reguł, nie mają składni.
Dodajmy składnię:
Dzięki tej składni każda zmienna jest używana dokładnie dwa razy, raz tam, gdzie jest związana i raz tam, gdzie jest używana. To pozwala nam zdystansować się od konkretnej składni i spojrzeć na ten termin jako wykres, na którym zmienne i terminy są krawędziami.
Ze złożoności algorytmicznej możemy teraz korzystać ze wskaźników nie ze zmiennej na spoiwo, ale ze spoiwa na zmienną i mieć podstawienia w stałym czasie.
Co więcej, ta zmiana formuły pozwala nam śledzić usuwanie, kopiowanie i udostępnianie z większą wiernością. Można pisać reguły, które stopniowo kopiują (lub usuwają) termin podczas udostępniania podtermów. Można to zrobić na wiele sposobów. W niektórych ograniczonych ustawieniach wygrane są dość zaskakujące .
Zbliża się to do tematów sieci interakcji, kombinatorów interakcji, wyraźnego podstawienia, logiki liniowej, optymalnej oceny Lampinga, udostępniania wykresów, logiki światła i innych.
Wszystkie te tematy są dla mnie bardzo ekscytujące i chętnie podam bardziej szczegółowe odniesienia, ale nie jestem pewien, czy którekolwiek z nich jest dla ciebie przydatne i jakie są twoje zainteresowania.
źródło
Twoja struktura danych działa, ale nie będzie bardziej wydajna niż inne podejścia, ponieważ musisz skopiować każdy argument przy każdej redukcji wersji beta i musisz wykonać tyle kopii, ile jest wystąpień zmiennej powiązanej. W ten sposób niszczycie dzielenie pamięci między subtermami. W połączeniu z faktem, że proponujesz nieczyste rozwiązanie, które wymaga manipulacji wskaźnikiem, a zatem jest bardzo podatne na błędy, prawdopodobnie nie jest warte kłopotów.
Ale byłbym zachwycony widząc eksperyment! Możesz wziąć
lambda
i zaimplementować go ze swoją strukturą danych (OCaml ma wskaźniki, nazywane są referencjami ). Bardziej lub mniej, po prostu trzeba wymienićsyntax.ml
inorm.ml
ze swoimi wersjami. To mniej niż 150 linii kodu.źródło
Inne odpowiedzi dotyczą głównie kwestii związanych z wdrażaniem. Ponieważ wspominasz o swojej głównej motywacji jako robieniu dowodów matematycznych bez zbytniej księgowości, oto główny problem, jaki z tym widzę.
Kiedy mówisz „funkcja, która odwzorowuje każdą zmienną na segregator, w którego zasięgu się ona znajduje”: typ wyjściowy tej funkcji jest z pewnością nieco subtelniejszy niż to sprawia, że brzmi! W szczególności funkcja musi przyjmować wartości w coś w rodzaju „spoiwa rozważanego terminu” - tj. Jakiś zestaw, który różni się w zależności od terminu (i oczywiście nie jest pod żadnym względem podzbiorem większego zestawu otoczenia). Tak więc w podstawieniu nie możesz po prostu „wziąć unii funkcji wiązania”: musisz także ponownie zindeksować ich wartości, zgodnie z pewną mapą od segregatorów w oryginalnych terminach do segregatorów w wyniku podstawienia.
Te reindeksacje z pewnością powinny być „rutynowe”, w tym sensie, że można je rozsądnie zamiatać pod dywan lub ładnie zapakować pod względem jakiejś funkcjonalności lub natury. To samo dotyczy księgowości związanej z pracą z nazwanymi zmiennymi. Ogólnie rzecz biorąc, wydaje mi się prawdopodobne, że przy takim podejściu byłoby co najmniej tyle samo księgowości, co w przypadku bardziej standardowych podejść.
Pomijając to, jest to bardzo atrakcyjne pod względem koncepcyjnym podejście i chciałbym zobaczyć, jak to dokładnie opracowano - mogę sobie wyobrazić, że może rzucić inne światło na niektóre aspekty składni niż standardowe podejście.
źródło
Lazy.t
zastosowania, którego używam poniżej).Ogólnie rzecz biorąc, uważam, że jest to fajna reprezentacja, ale wymaga pewnej księgowości ze wskazówkami, aby uniknąć zerwania wiążących linków. Można by chyba zmienić kod, aby używał zmiennych pól, ale kodowanie w Coq byłoby wtedy mniej bezpośrednie. Nadal jestem przekonany, że jest to bardzo podobne do HOAS, chociaż struktura wskaźnika jest wyraźna. Jednak obecność
Lazy.t
sugeruje, że możliwe jest oszacowanie kodu w niewłaściwym czasie. W moim kodzie nie ma to miejsca, ponieważ w danymforce
momencie może wystąpić tylko podstawienie zmiennej zmienną (a nie na przykład ocena).źródło