Kalkül mit Reflexion


23

Ich suche nach einem einfachen Kalkül, das die Überlegungen zur Reflexion unterstützt , nämlich die Introspektion und Manipulation von laufenden Programmen.

Gibt es eine untypisierte λ Kalkulus-Erweiterung, mit der man λ Terme in eine Form umwandeln kann, die syntaktisch manipuliert und anschließend ausgewertet werden kann?

Ich stelle mir vor, dass der Kalkül zwei zusätzliche Hauptbegriffe hat:

  • reflect v : nimmtv und erzeugt eine Darstellungv abänderbar zur syntaktischen Manipulation.
  • eval v : Nimmt eine syntaktische Darstellung eines Begriffs und wertet ihn aus.

Zur Unterstützung der Reflexion ist eine syntaktische Darstellung von Begriffen erforderlich. Es würde ungefähr so ​​aussehen:

  • würde als ein Term ( L A M R ( e ) ) dargestellt , wobei R ( e ) die reflektierte Version von e ist ,λx.e(LAM R(e))R(e)e
  • würde dargestellt als Term ( A P P R ( e ) R ( e ' ) ) unde e(APP R(e) R(e))
  • würden dargestellt als ( V A R x ) .x(VAR x)

Mit dieser Darstellung könnte der Mustervergleich zum Manipulieren von Begriffen verwendet werden.

Aber wir stoßen auf ein Problem. und e v a l müssen als Terme codiert werden, ebenso wie Pattern Matching. Der Umgang damit scheint unkompliziert zu sein, wenn Sie R E F L E C T , E V A L und M A T C H hinzufügen. Muss ich jedoch andere Begriffe hinzufügen, um die Manipulation dieser zu unterstützen?reflectevalREFLECTEVALMATCH

Es gibt Designentscheidungen, die getroffen werden müssen. Was soll die oben erwähnte - Funktion mit dem Körper von r e f l e c t und e v a l tun ? Sollte R ( - ) den Körper transformieren oder nicht?R()reflectevalR()

Da ich nicht so sehr daran interessiert bin, Reflexion selbst zu studieren - der Kalkül würde als Vehikel für andere Forschungen dienen - möchte ich das Rad nicht neu erfinden.

Gibt es Kalküle, die mit den oben beschriebenen übereinstimmen?

Soweit ich das beurteilen kann, sind Kalküle wie MetaML, die in einem Kommentar vorgeschlagen wurden, weit fortgeschritten, bieten jedoch nicht die Möglichkeit, bereits erstellte Codefragmente zu strukturieren und zu dekonstruieren.

Eine Sache, die ich tun möchte, ist die folgende:

  • let x=λy.y in reflect x(LAM (VAR y) (VAR y))

Führen Sie dann einen Mustervergleich für das Ergebnis durch, um einen völlig anderen Ausdruck zu erstellen.

Dies ist sicherlich keine konservative Erweiterung des Kalküls, und die Metatheorie dürfte hässlich sein, aber dies ist eine Art Punkt für meine Anwendung. Ich möchte λ -Abstraktionen auseinander brechen .λλ


MetaML ist eine typisierte reflektierende Sprache, in der der Operator der Klammerung Ihr REFLECT ausführt und die EVAL aufhebt. Die Eingabe ist einfach, aber Sie können das Fragment, das von modal S4 geerbt wurde, in Arbeiten wie diesem Dokument sehen , die Ihnen möglicherweise helfen.
ex0du5

@ ex0du5: Danke, aber das geht nicht weit genug, soweit ich das beurteilen kann. Sicher, ich kann Code in verschiedenen Phasen erstellen, aber ich scheine nicht in der Lage zu sein, Begriffe auseinander zu reißen. (Ich werde genauer lesen, um zu sehen, ob ich etwas verpasst habe.)
Dave Clarke

Schema (ohne die Veränderlichkeit und andere Komplikationen)?
Gilles 'SO- hör auf böse zu sein'

@ Gilles: Schema ist eine Programmiersprache, kein Kalkül. Außerdem glaube ich nicht, dass es tun kann, was ich will.
Dave Clarke

@ DaveClarke Eine Programmiersprache ist ein Kalkül mit vielen Warzen. Ein Schemakern scheint auf den ersten Blick geeignet zu sein, aber ich habe nicht genug über Ihre Anforderungen nachgedacht, um sicherzugehen. Was denkst du würde nicht funktionieren? (Kommen Sie vorbei, um zu plaudern, wenn Sie möchten.)
Gilles 'SO - hören Sie auf, böse zu sein'

Antworten:


15

Jean Louis Krivine führte einen abstrakten Kalkül ein, der die "Krivine-Maschine" auf sehr nicht-triviale Weise erweitert (beachten Sie, dass die Krivine-Maschine die call / cc-Anweisung von lisp bereits unterstützt):

Er führt einen „Zitat“ Operator in diesem Artikel auf die folgende Weise definiert: wenn a λ -term, note n & phi; das Bild von φ durch eine Bijektion π : & Lgr; N von Lambda - Ausdrücke auf natürliche Zahlen. Anmerkung ¯ n ist die Kirchennummer, die n N entspricht . Krivine definiert den Operator χ durch die Bewertungsregel: χ φ φ ¯ n φϕλnϕϕπ:ΛNn¯nNχ

χ ϕϕ nϕ¯
Ich glaube, dass die Zauberei von Kleene zeigen wird, dass dies ausreicht, um das zu tun, was Sie möchten: dh ein Zitat und Bewertungsoperatoren zu definieren, wenn berechenbar ist.π

Beachten Sie, dass Krivine eine notorisch schwierige Lektüre ist (seien Sie bitte nicht böse, wenn Sie dies lesen, Jean-Louis!), Und einige Forscher haben den karitativen Akt unternommen, um den technischen Inhalt besser lesbar zu machen. Sie könnten versuchen, einen Blick auf diese Notizen von Christophe Raffali zu werfen .

Hoffe das hilft!


Mir fällt ein, dass es einen weiteren Hinweis gibt, der für Ihre Interessen relevant sein könnte: Der Pure Pattern Calculus von Jay und Kesner formalisiert eine Variante des Kalküls, die eine einfache Abstraktion über eine Variable zu einer Abstraktion über ein Muster, das ein Musterkalkül darstellt, erweitert selbst. Dies ist phänomenal aussagekräftig und ermöglicht es insbesondere, eine Anwendung selbst zu dekonstruieren: Wenn ich mich nicht irre, lautet der Begriff:λ

(λ(x y).x)((λx.x x) (λy.y))

reduziert sich auf . Auch hier bin ich der Meinung, dass dies mehr als genug ist, um die Operatoren quote und eval zu implementieren .λx.x x


Ich würde diese scheinbar vernünftige Antwort gerne unterstützen, aber ich habe keine Ahnung, ob sie überhaupt die Frage zu beantworten beginnt.
Raphael

@Raphael lese die Artikel und finde es heraus :) In Wahrheit ist dies nur eine unvollständige Antwort: Die Artikel formalisieren tatsächlich ein wichtiges Merkmal von lisp, das im Lambda-Kalkül nicht zu finden ist: den QUOTE-Operator. Es gibt jedoch keine ausführliche metatheoretische Studie, sondern sie wird nur als Mittel eingeführt, um eine Art seltsame undurchsichtige Berechnung auszudrücken, um komplizierte Axiome der Mengenlehre zu verwirklichen.
Cody

1
Wenn ich mich richtig erinnere, können Sie in PPC keine Musterübereinstimmung bei Redexen vornehmen. Der Grund, den sie angegeben haben, ist der Konfluenz halber. Außerdem ist bei PPC die Musteranpassung bei der Anpassung streng, so dass sofort auf λ y normiert wird . y , dann schlägt der Versuch fehl, es mit dem Muster ( x y ) abzugleichen. (λx.x x) (λy.y)λy.y(x y)
Tag

1
Das einzige Zitat, das ich kenne, ist das von Lisp. Aber, wie ich mich erinnere, ändert es einfach alles, was zitiert wird, in ein syntaktisches Objekt. Die "function" nimmt ihr Argument unbewertet. Die Funktion r e f l e c t soll den Wert ihres Arguments nehmen (auswerten) und es in einen syntaktischen Ausdruck zurückverwandeln, der auswertet (wie) ?) auf diesen Wert. Wenn also die Krivine Formalismus beschäftigt sich mit der LISP q u o t e , erhalten wir bei weitem nicht , was in der Frage vorgeschlagen. quotereflectquote
Babou

8

Dies zu tun ist sehr schwierig, wenn nicht unmöglich, ohne den Zusammenfluss aufzugeben. Das heißt, ich vermute, Sie haben Recht mit einer haarigen Metatheorie. Auf der anderen Seite ist es möglich, eine Kombinationsrechnung zu entwerfen, die alle berechenbaren Funktionen ausdrückt und deren Begriffe vollständig überprüft werden können: siehe Jay und Give-Wilson .

Ich glaube jedoch, dass diese Fähigkeit Ihrer Gleichungstheorie einiges Schlechtes anhaben kann. Insbesondere können Sie in der Regel nur dann beweisen, dass zwei Werte gleich sind, wenn die bis zu Alpha-Äquivalenzen gleich sind.

Ich habe die mit Krivine verknüpfte Papierkodierung noch nicht gelesen, aber ich sollte beachten, dass Sie in der klassischen Logik im Wesentlichen nur zwei Dinge haben: wahr und falsch. Alles ist gleichbedeutend mit einer davon. Das heißt, Sie neigen sowieso dazu, eine zusammengebrochene Gleichungstheorie zu haben.


1
Beachten Sie, dass der Krivine-Kalkül kein Kalkül von Sätzen ist, sondern von Realisierern für diese, die eine hochgradig nicht-triviale Gleichungstheorie haben.
Cody

5

In der Theorie der Programmiersprachen wird die Funktion, über die Sie sprechen, normalerweise als "Anführungszeichen" bezeichnet. Zum Beispiel hat John Longley in einigen seiner Arbeiten darüber geschrieben, siehe dieses Papier .

Wenn Sie nur theoretischen Überlegungen nachgehen (im Gegensatz zu einer wirklich nützlichen Implementierung), können Sie die Dinge vereinfachen, indem Sie angeben, dass quote(oder reflectwie Sie es nennen) der Typ von Ganzzahlen zugeordnet ist, natindem Sie einen Gödel-Code seines Arguments zurückgeben. Sie können die Zahl dann wie einen abstrakten Syntaxbaum zerlegen. Darüber hinaus brauchen Sie nicht, evalweil das in der Sprache implementiert werden kann - es ist im Wesentlichen ein Dolmetscher für die Sprache.

nmφn(m)φnnλquote

Wenn Sie mir sagen, wonach Sie suchen, kann ich Ihnen möglicherweise genauere Referenzen geben.

Hier ist übrigens ein offenes Problem:

λquoteξ Regel erhältst.

ξ

e1e2λx.e1λx.e2
λλquotequote
e1e2quotee1quotee2,
quote((λx.x)y)quotey.
quoteλ

βquoteλξ

ξβ

Die folgende Arbeit zeigt einige Probleme mit der (ξ) -Gleichung: Die Lambda-Rechnung ist algebraisch, Peter Selinger. Interessant, etwas Neues, das mir nicht bewusst war! Cool.
Transfinite Numbers

4

Hier ist eine alternative Antwort, anstatt meinen nominalen Ansatz zu verwenden, der noch experimentell ist, gibt es einen etablierteren Ansatz, der auf das Papier zurückgeht:

LEAP: Eine Sprache mit Eval und Polymorphismus
Frank Pfenning und Peter Lee
https://www.cs.cmu.edu/~fp/papers/tapsoft89.pdf

Das Papier beginnt mit:

Dies führte uns dann zu der von Reynolds zuerst gestellten Frage, ob stark typisierte Sprachen metazirkuläre Interpreten zulassen. Konventionelle Weisheit schien darauf hinzudeuten, dass die Antwort "Nein" war. Unsere Antwort lautet "Fast".

Bitte beachten Sie, dass LEAP viel stärker ist als das, was das OP will. Zunächst wird es getippt. Und zweitens wird nach Metacircularity gefragt, was zum Beispiel bedeutet, dass eval eine eigene Definition ausführen kann. In Prolog erhalten Sie die Metacircularity for solve / 1:

solve(true).
solve((A,B)) :- solve(A), solve(B).
solve(H) :- clause(H,B), solve(B).

Wenn Sie die folgende Klausel hinzufügen, um / 1 zu lösen:

solve(clause(H,B)) :- clause(H,B).

Und wenn Sie dafür sorgen, gibt Klausel / 2 auch die Klauseln von solve / 1 zurück. Sie können dann solve (solve (...)) aufrufen und sehen, wie solve sich selbst ausführt.

Fragen der Selbstrepräsentation geben noch Anlass zur Recherche, siehe zum Beispiel:

Selbstdarstellung im Girards-System U
Matt Brown, Jens Palsberg
http://compilers.cs.ucla.edu/popl15/popl15-full.pdf


3

Das Problem wird in der Nähe von Proof-Assistenten wie Coq und Isabelle / HOL identifiziert. Es steht unter dem Akronym HOAS . Es gibt einige Behauptungen um λ-Prolog herum, dass durch den neuen ∇-Quantifizierer solche Dinge getan werden können. Aber ich konnte diese Behauptung noch nicht in den Griff bekommen. Ich denke, die wichtigste Erkenntnis, die ich bisher erhalten habe, ist, dass es keinen bestimmten Ansatz gibt, es gibt ein paar mögliche Ansätze.

Meine eigene Einstellung , die noch nicht fertig ist , ist inspiriert von einem kürzlich erschienenen Artikel von Paulson über den Nachweis von Gödels Unvollständigkeit. Ich würde die Ordner auf Objektebene in Verbindung mit einer Datenstruktur verwenden, die Namen auf Metaebene enthält. Grundsätzlich eine ähnliche, aber unterschiedliche Datenstruktur wie die aus dem OP und mit der Codierung der Kirche, da ich an abhängigen Typen interessiert bin:

datatype Expr = var Name                 /* written as n */
              | app Expr Expr            /* written as s t */
              | abs Name Expr Expr       /* written as λn:s.t */

Die Ausdrücke auf Metaebene können von den Ausdrücken auf Objektebene dadurch unterschieden werden, dass wir die Variablennamen n, m usw. verwenden, um Namen zu bezeichnen. Während wir auf Objektebene die Variablennamen x, y, .. etc .. verwenden. Die Interpretation eines Meta-Terms in der Objektlogik würde dann wie folgt funktionieren. Schreiben wir [t] σ für die Interpretation des Nominalterms t im Nominalkontext σ, der einen Objektterm ergeben soll. Wir hätten dann:

 [n]σ = lookup σ n
 [s t]σ = [s]σ [t]σ
 [λn:s.t]σ = λx:[s]σ.[t]σ,n:x

Das Obige würde definieren, was das OP eine EVAL-Funktion nennt. Kleiner Unterschied zu Paulson, σ ist nur eine endliche Liste und keine funktionale. Meiner Meinung nach wäre es nur möglich, eine EVAL-Funktion und keine REFLECT-Funktion einzuführen. Da auf der Objektebene möglicherweise eine gewisse Gleichheit vorliegt, sind die verschiedenen Lambda-Ausdrücke gleich. Was Sie tun müssten, wäre eval zu nutzen, um möglicherweise auch über Reflexion nachzudenken, wenn Sie das Bedürfnis haben.

Sie müssten zu Extremen wie Prolog gehen, wo nichts erweitert wird, wenn Sie die Mauer zwischen nominal und nicht nominal niederreißen möchten. Aber wie das Beispiel des λ-Prolog-Systems zeigt, gibt es im Fall höherer Ordnung zusätzliche Probleme, die zum Beispiel nur durch die Einführung neuer Mittel wie eines as-Quantifizierers auf logische Weise überwunden werden können!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.