Clojure warning / Fehler bei Tail-Call-Optimierung fehlgeschlagen

8

In Scala 2.8.x wurde eine neue Annotation ( @tailrec ) hinzugefügt, die einen Kompilierungsfehler ergibt, wenn der Compiler keine Tail-Call-Optimierung für die mit Annotationen versehene Methode durchführen kann.

Gibt es eine ähnliche Einrichtung in Clojure in Bezug auf loop/recur ?

BEARBEITEN: Nachdem ich die erste Antwort auf meine Frage (Danke, Bozhidar Batsov) gelesen und weiter in den Clojure-Dokumenten gesucht hatte, stieß ich auf folgendes:

(Wiederholungsexpres *)
Analysiert die Ausdrücke in der Reihenfolge und bindet dann parallel die Bindungen des Rekursionspunkts an die Werte der Ausdrücke. Wenn der Rekursionspunkt eine Fn-Methode war, werden die Params erneut eingebunden. Wenn der Rekursionspunkt eine Schleife ist, bindet er die Schleifenbindungen erneut. Die Ausführung springt dann zum Rekursionspunkt zurück. Der rekursive Ausdruck muss genau mit der Genauigkeit des Rekursionspunkts übereinstimmen. Insbesondere, wenn der Rekursionspunkt die Spitze einer variadischen fn-Methode war, gibt es keine Sammlung von Restargumenten - eine einzelne seq (oder null) sollte übergeben werden. Wiederholung in einer anderen als eine Endposition ist ein Fehler .

Beachten Sie, dass recur das einzige nicht stapelaufbauende Schleifenkonstrukt in Clojure ist. Es gibt keine Tail-Call-Optimierung und die Verwendung von Self-Calls für das Schleifen von unbekannten Grenzen wird abgeraten. recur ist funktional und seine Verwendung in der Endposition wird vom Compiler überprüft [emphasis is mine].

%Vor%     
Ralph 26.04.2010, 11:08
quelle

2 Antworten

4

Es gibt keine Tail-Call-Optimierung, wenn Sie Schleife / Wiederholung AFAIK verwenden. Ein Zitat aus der offiziellen Dokumentation:

  

In Abwesenheit von veränderlichen lokalen   Variablen, Schleifen und Iterationen müssen   nehmen Sie eine andere Form als in   Sprachen mit eingebauten für oder während   Konstrukte, die von gesteuert werden   Zustand ändern. In funktionalen   Sprachen Looping und Iteration sind   ersetzt / implementiert über rekursiv   Funktionsaufrufe. Viele solche Sprachen   garantieren, dass Funktionsaufrufe getätigt werden   Heckposition nicht Stack verbrauchen   Raum und damit rekursive Schleifen   nutze konstanten Raum. Seit Clojure   verwendet die Java-Aufrufkonventionen, es   kann und macht nicht dasselbe   Tail Call-Optimierung garantiert.   Stattdessen bietet es das wiederkehrende Spezial   Operator, der Konstantenraum ausführt   Rekursives Looping durch Rebinding und   zur nächsten umschließenden Schleife springen   oder Funktionsrahmen. Während nicht als   allgemein als Tail-Call-Optimierung, es   lässt die meisten gleich elegant zu   Konstruiert und bietet den Vorteil   zu überprüfen, dass Aufrufe wiederkehren können   nur in einer Schwanzposition passieren.

    
Bozhidar Batsov 26.04.2010, 11:14
quelle
5

Eigentlich ist die Situation in Scala w.r.t. Tail Call Optimization ist die gleiche wie in Clojure : Es ist möglich, es in einfachen Situationen wie Selbstrekursion durchzuführen, aber nicht in allgemeinen Situationen wie dem Aufruf einer beliebigen Funktion in der Endposition.

Dies liegt an der Funktionsweise der JVM - damit TCO auf der JVM arbeiten kann, müsste die JVM selbst dies unterstützen, was sie derzeit nicht tut (obwohl sich dies möglicherweise ändern könnte) JDK7 wird veröffentlicht).

Siehe z.B. diesen Blogeintrag für eine Diskussion über TCO und Trampolinspringen in Scala. Clojure hat genau die gleichen Eigenschaften, um nicht-Stack-konsumierende (= Tail-Call-optimierte) Rekursion zu ermöglichen; Dies umfasst das Auslösen eines Kompilierungsfehlers, wenn der Benutzercode versucht, recur in der Nicht-Endposition aufzurufen.

    
Michał Marczyk 26.04.2010 15:29
quelle

Tags und Links