Algol 60
Hier ist eine Funktion boolean procedure
, die genau das tut, wonach die Frage verlangt (Hinweis: Algol 60 wird anhand einer Liste von Token definiert, ohne dass die Syntax für diese festgelegt wird. Im Folgenden wird die Marst-Syntax verwendet, um die einzelnen Token darzustellen, aus denen das Programm besteht):
boolean procedure recursion detector(n);
boolean n;
begin
own boolean nested, seen nested;
boolean was nested, retval;
was nested := nested;
begin if nested then seen nested := true end;
nested := true;
retval := n; comment "for the side effects, we ignore the result";
nested := was nested;
retval := seen nested;
begin if ! nested then seen nested := false end;
recursion detector := retval
end;
Nachprüfung
Hier ist der Testcode, den ich verwendet habe:
procedure outboolean(c, b);
integer c;
boolean b;
begin
if b then outstring(c, "true\n") else outstring(c, "false\n")
end;
begin
outboolean(1, recursion detector(false));
outboolean(1, recursion detector(true));
outboolean(1, recursion detector(recursion detector(false)));
outboolean(1, recursion detector(false | recursion detector(true)));
outboolean(1, recursion detector(false & recursion detector(true)));
outboolean(1, recursion detector(recursion detector(recursion detector(false))))
end
Wie erwartet ist die Ausgabe:
false
false
true
true
true comment "because & does not short-circuit in Algol 60";
true
Erläuterung
Algol 60 hat eine andere Bewertungsreihenfolge als die meisten Sprachen, die eine eigene Logik hat und tatsächlich viel leistungsfähiger und allgemeiner als die typische Bewertungsreihenfolge ist, aber für Menschen ziemlich schwer zu verstehen ist (und auch ziemlich schwer für Computer effizient zu implementieren, weshalb es für Algol geändert wurde 68). Dies ermöglicht eine Lösung ohne Betrug (das Programm muss nicht auf den Analysebaum oder ähnliches schauen, und im Gegensatz zu fast allen anderen Lösungen hier würde dies gut funktionieren, wenn der verschachtelte Aufruf über eine erfolgt wäre FFI).
Ich beschloss auch, ein paar andere Macken der Sprache zu zeigen. (Insbesondere können Variablennamen Leerzeichen enthalten. Dies ist für die Lesbarkeit ziemlich nützlich, da sie keine Unterstriche enthalten können. Ich mag auch die Tatsache, dass der Kommentarindikator das wörtliche Wort comment
in den meisten Syntaxcodierungen ist. Algol 68 fand dies kurz gesagt ziemlich umständlich Kommentare und ¢
als Alternative eingeführt. Die Anführungszeichen um den Kommentarkörper werden normalerweise nicht benötigt. Ich füge sie nur hinzu, um Klarheit zu schaffen und um zu verhindern, dass der Kommentar versehentlich endet, wenn ich ein Semikolon eingebe.) Ich mag die allgemeinen Konzepte der Sprache wirklich sehr (wenn nicht die Details), aber es ist so ausführlich, dass ich es selten auf PPCG verwenden kann.
Algol 60 unterscheidet sich hauptsächlich von den Sprachen, die es inspiriert hat (wie Algol 68 und indirekt C, Java usw .; Leute, die K & R C kennen, werden diese Syntax für Funktionen wahrscheinlich erkennen), dass ein Funktionsargument ein bisschen wie behandelt wird ein kleines Lambda für sich; Wenn Sie beispielsweise das Argument 5
einer Funktion geben, die nur die Zahl 5 ist, aber wenn Sie das Argument x+1
angeben, erhalten Sie genau das, was Sie angegeben haben, das Konzept von " x
plus 1" und nicht das Ergebnis von x
plus 1. Der Unterschied hier Wenn x
Änderungen vorgenommen werden, wird beim Versuch, das betreffende Funktionsargument auszuwerten, der neue Wert von angezeigtx
. Wenn ein Funktionsargument nicht innerhalb der Funktion ausgewertet wird, wird es auch nicht außerhalb der Funktion ausgewertet. Wenn es innerhalb der Funktion mehrmals ausgewertet wird, wird es jedes Mal separat ausgewertet (vorausgesetzt, dies kann nicht optimiert werden). Dies bedeutet, dass es möglich ist, beispielsweise die Funktionalität von if
oder while
in einer Funktion zu erfassen .
In diesem Programm nutzen wir die Tatsache, dass, wenn ein Aufruf einer Funktion in einem Argument für diese Funktion erscheint, die Funktion rekursiv ausgeführt wird (da das Argument genau an dem Punkt oder den Punkten ausgewertet wird, an denen die Funktion es auswertet nicht früher oder später, und dies muss notwendigerweise innerhalb des Funktionskörpers sein). Dies reduziert das Problem auf das Erkennen, ob die Funktion rekursiv ausgeführt wird, was viel einfacher ist. Alles, was Sie benötigen, ist eine threadlokale Variable, die erkennt, ob ein rekursiver Aufruf vorliegt (und in diesem Fall eine weitere, um Informationen in die andere Richtung zu übertragen). Wir können eine statische Variable verwenden (dhown
) zu diesem Zweck, da Algol 60 Single-Threaded ist. Danach müssen wir nur noch alles so zurücksetzen, wie es war, damit die Funktion bei mehrmaligem Aufruf korrekt funktioniert (gemäß den PPCG-Regeln).
Die Funktion gibt im Moment nicht den gewünschten Wert aus den internen Aufrufen zurück (zumindest wenn Sie davon ausgehen, dass sie nur in ihren Argumenten nach Selbstaufrufen suchen sollten , anstatt sich selbst zu zählen). Diese Arbeit zu machen ist ziemlich einfach, wenn man dieselben allgemeinen Prinzipien verwendet, aber komplexer und würde die Funktionsweise der Funktion verdecken. Wenn dies zur Beantwortung der Frage als notwendig erachtet wird, sollte es nicht zu schwierig sein, dies zu ändern.
print(func(), func(func()))
oder wird die Funktion erst direkt nach ihrer Definition auf oberster Ebene aufgerufen?