Das Problem der Darstellung gebundener Variablen in der Syntax und insbesondere der Substitution zur Vermeidung von Captures ist bekannt und hat eine Reihe von Lösungen: benannte Variablen mit Alpha-Äquivalenz, De-Bruijn-Indizes, lokale Namenslosigkeit, nominale Mengen usw.
Aber es scheint einen anderen ziemlich offensichtlichen Ansatz zu geben, den ich dennoch nirgendwo verwendet habe. In der Grundsyntax haben wir nämlich nur einen "Variablen" -Term, der mit , und dann geben wir separat eine Funktion, die jede Variable einem Ordner zuordnet, in dessen Bereich sie liegt. Also ein λ- Term wie
würde geschrieben werden . ( λ . ∙ ∙ ) , und die Funktion würde das erste ∙ auf das erste λ und das zweite ∙ auf das zweite λ abbilden . Es ist also ein bisschen wie bei de Bruijn-Indizes, nur anstatt " λ s zählen" zu müssen, wenn Sie den Begriff verlassen, um das entsprechende Bindemittel zu finden, bewerten Sie einfach eine Funktion. (Wenn dies als Datenstruktur in einer Implementierung dargestellt wird, würde ich daran denken, jedes Objekt mit variablem Term mit einem einfachen Zeiger / Verweis auf das entsprechende Objekt mit Binderterm auszustatten.)
Offensichtlich ist dies nicht sinnvoll, um Syntax auf eine Seite zu schreiben, die der Mensch lesen kann, aber es gibt auch keine de Bruijn-Indizes. Es scheint mir, dass es mathematisch absolut sinnvoll ist, und insbesondere macht es die Substitution, die das Erfassen vermeidet, sehr einfach: Geben Sie einfach den Begriff ein, den Sie ersetzen, und nehmen Sie die Vereinigung der Bindungsfunktionen. Es ist wahr, dass es keinen Begriff von "freier Variable" gibt, aber (wieder) auch nicht wirklich de Bruijn-Indizes; In beiden Fällen wird ein Begriff, der freie Variablen enthält, als Begriff mit einer Liste von "Kontext" -Bindemitteln dargestellt.
Vermisse ich etwas und es gibt einen Grund, warum diese Darstellung nicht funktioniert? Gibt es Probleme, die es so viel schlimmer machen als die anderen, dass es sich nicht lohnt, darüber nachzudenken? (Das einzige Problem, an das ich im Moment denken kann, ist, dass die Menge der Begriffe (zusammen mit ihren Bindungsfunktionen) nicht induktiv definiert ist, aber das scheint nicht unüberwindbar.) Oder gibt es tatsächlich Orte, an denen sie verwendet wurden?
quelle
Antworten:
Die Antworten von Andrej und Łukasz machen gute Punkte, aber ich wollte zusätzliche Kommentare hinzufügen.
Um das zu wiederholen, was Damiano gesagt hat, ist diese Art der Darstellung der Bindung mithilfe von Zeigern diejenige, die von Beweisnetzen vorgeschlagen wird, aber der früheste Ort, an dem ich sie für Lambda-Begriffe sah, war in einem alten Aufsatz von Knuth:
Diese Art der grafischen Darstellung von Lambda-Begriffen wurde Anfang der 1970er Jahre in zwei Thesen unabhängig voneinander (und eingehender) untersucht, sowohl von Christopher Wadsworth (1971, Semantik und Pragmatik des Lambda-Kalküls ) als auch von Richard Statman (1974, Structural Complexity) von Beweisen ). Heutzutage werden solche Diagramme oft als "λ-Graphen" bezeichnet (siehe zum Beispiel dieses Papier ).
Beachten Sie, dass der Begriff in Knuths Diagramm linear ist , in dem Sinne, dass jede freie oder gebundene Variable genau einmal vorkommt - wie andere bereits erwähnt haben, müssen nicht triviale Probleme und Entscheidungen getroffen werden, um diese Art der Darstellung auf Nicht zu erweitern -lineare Terme.
quelle
Ich bin mir nicht sicher, wie Ihre Variable-zu-Binder-Funktion dargestellt wird und für welchen Zweck Sie sie verwenden möchten. Wenn Sie Back-Pointer verwenden, ist die rechnerische Komplexität der Substitution, wie Andrej feststellte, nicht besser als die klassische Alpha-Umbenennung.
Aus Ihrem Kommentar zu Andrejs Antwort schließe ich, dass Sie in gewissem Maße daran interessiert sind, etwas zu teilen. Ich kann hier einen Beitrag leisten.
In einem typischen typisierten Lambda-Kalkül haben Schwächung und Kontraktion im Gegensatz zu anderen Regeln keine Syntax.
Fügen wir eine Syntax hinzu:
Mit dieser Syntax wird jede Variable genau zweimal verwendet, einmal dort, wo sie gebunden ist, und einmal dort, wo sie verwendet wird. Dies ermöglicht es uns, uns von einer bestimmten Syntax zu distanzieren und den Begriff als Diagramm zu betrachten, in dem Variablen und Begriffe Kanten sind.
Aufgrund der algorithmischen Komplexität können wir jetzt Zeiger nicht von einer Variablen zu einem Binder, sondern von Binder zu Variable verwenden und Substitutionen in einer konstanten Zeit haben.
Darüber hinaus können wir mit dieser Neuformulierung das Löschen, Kopieren und Teilen mit größerer Genauigkeit verfolgen. Man kann Regeln schreiben, die einen Begriff schrittweise kopieren (oder löschen), während Subterme geteilt werden. Dafür gibt es viele Möglichkeiten. In einigen eingeschränkten Einstellungen sind die Gewinne ziemlich überraschend .
Dies nähert sich den Themen Interaktionsnetze, Interaktionskombinatoren, explizite Substitution, lineare Logik, optimale Bewertung von Lamping, gemeinsame Nutzung von Diagrammen, Lichtlogik und anderem.
All diese Themen sind für mich sehr aufregend und ich würde gerne spezifischere Referenzen geben, aber ich bin mir nicht sicher, ob dies für Sie nützlich ist und was Ihre Interessen sind.
quelle
Ihre Datenstruktur funktioniert, ist jedoch nicht effizienter als andere Ansätze, da Sie jedes Argument bei jeder Beta-Reduzierung kopieren müssen und so viele Kopien erstellen müssen, wie die gebundene Variable vorkommt. Auf diese Weise zerstören Sie die Speicherfreigabe zwischen Subtermen. In Kombination mit der Tatsache, dass Sie eine nicht reine Lösung vorschlagen, die Zeigermanipulationen beinhaltet und daher sehr fehleranfällig ist, ist es wahrscheinlich nicht die Mühe wert.
Aber ich würde mich freuen, ein Experiment zu sehen! Sie können
lambda
es mit Ihrer Datenstruktur übernehmen und implementieren (OCaml hat Zeiger, sie werden Referenzen genannt ). Mehr oder weniger müssen Sie nursyntax.ml
undnorm.ml
durch Ihre Versionen ersetzen . Das sind weniger als 150 Codezeilen.quelle
Andere Antworten befassen sich hauptsächlich mit Implementierungsproblemen. Da Sie Ihre Hauptmotivation als mathematische Beweise ohne zu viel Buchhaltung erwähnen, ist hier das Hauptproblem, das ich damit sehe.
Wenn Sie sagen "eine Funktion, die jede Variable einem Ordner zuordnet, in dessen Bereich sie liegt": Der Ausgabetyp dieser Funktion ist sicherlich etwas subtiler, als es sich anhört! Insbesondere muss die Funktion Werte in so etwas wie „den Bindemitteln des betrachteten Begriffs“ annehmen - dh einer Menge, die je nach Begriff variiert (und offensichtlich keine Teilmenge einer größeren Umgebungsmenge in irgendeiner nützlichen Weise ist). Bei der Substitution können Sie also nicht einfach „die Vereinigung der Bindungsfunktionen übernehmen“: Sie müssen auch ihre Werte neu indizieren, gemäß einer Zuordnung von Bindemitteln in den ursprünglichen Begriffen zu Bindemitteln im Ergebnis der Substitution.
Diese Neuindizierungen sollten sicherlich „Routine“ sein, in dem Sinne, dass sie vernünftigerweise entweder unter den Teppich gekehrt oder in Bezug auf eine Art Funktionalität oder Natürlichkeit gut verpackt werden könnten. Gleiches gilt jedoch für die Buchhaltung bei der Arbeit mit benannten Variablen. Insgesamt scheint es mir also wahrscheinlich, dass mit diesem Ansatz mindestens so viel Buchhaltung verbunden ist wie mit Standardansätzen.
Abgesehen davon ist es jedoch ein konzeptionell sehr ansprechender Ansatz, und ich würde es gerne sorgfältig ausgearbeitet sehen - ich kann mir gut vorstellen, dass er einige Aspekte der Syntax in einem anderen Licht erscheinen lässt als die Standardansätze.
quelle
Lazy.t
Insgesamt denke ich, dass es eine coole Darstellung ist, aber es beinhaltet einige Buchhaltung mit Zeigern, um das Brechen von Bindungslinks zu vermeiden. Es wäre möglich, den Code zu ändern, um veränderbare Felder zu verwenden, aber die Codierung in Coq wäre dann weniger direkt. Ich bin immer noch davon überzeugt, dass dies HOAS sehr ähnlich ist, obwohl die Zeigerstruktur explizit gemacht wird. Das Vorhandensein von
Lazy.t
impliziert jedoch, dass ein Code möglicherweise zur falschen Zeit ausgewertet wird. Dies ist in meinem Code nicht der Fall, da zur Zeit nur eine Ersetzung einer Variablen durch eine Variable erfolgen kannforce
(und beispielsweise keine Auswertung).quelle