2010-05-31 8 views
5

Ich gebe zu, dass das Folgende eine ziemlich schreckliche Beschreibung dessen ist, was ich tun möchte. Entschuldigung im Voraus. Bitte stellen Sie Fragen, um mir zu erklären. :-)Common Lisp Condition System für die Übertragung der Kontrolle

ich geschrieben habe ETLs (Extract, Transform, Load) in anderen Sprachen, die von einzelnen Operationen bestehen, die wie etwas aussehen:

// in class CountOperation 
IEnumerable<Row> Execute(IEnumerable<Row> rows) { 
    var count = 0; 
    foreach (var row in rows) { 
     row["record number"] = count++; 
     yield return row; 
    } 
} 

Dazu Zeichenfolge eine Anzahl dieser Operationen zusammen, und Rufen Sie den Dispatcher auf, der für den Aufruf von Operationen und das Übertragen von Daten zwischen ihnen zuständig ist.

Ich versuche etwas ähnliches in Common Lisp zu tun, und ich möchte die gleiche Grundstruktur verwenden, d. H. Jede Operation ist wie eine normale Funktion definiert, die eine Liste eingibt und eine Liste ausgibt, aber träge.

Ich kann define-condition eine Bedingung (have-value) für yield-ähnliches Verhalten zu verwenden, und ich kann es in einer einzigen Schleife laufen, und es funktioniert super. Ich bin die Definition der Operationen die gleiche Art und Weise, durch die Eingänge Looping:

(defun count-records (rows) 
    (loop for count from 0 
     for row in rows 
     do (signal 'have-value :value `(:count ,count @,row)))) 

Das Problem ist, wenn ich aneinanderzureihen mehrere Operationen möchten, und führen Sie sie. Mein erster Versuch, einen Dispatcher für diese Schreiben sieht ungefähr so ​​aus:

(let ((next-op ...)) ;; pick an op from the set of all ops 
    (loop 
    (handler-bind 
     ((have-value (...))) ;; records output from operation 
    (setq next-op ...) ;; pick a new next-op 
    (call next-op))) 

aber neu gestartet haben nur dynamischen Umfang: jeder Betrieb die gleichen Neustart Namen hat. Der Neustart ist kein Lisp-Objekt, das ich speichern kann, um den Status einer Funktion zu speichern: Es ist etwas, was Sie im Handler-Block mit dem Namen (Symbol) aufrufen, nicht eine Fortsetzung, die Sie für die spätere Verwendung speichern können.

Ist es möglich, hier etwas zu tun, was ich will? Oder bin ich besser dran, wenn ich einfach jede Operationsfunktion explizit auf ihre Eingabewarteschlange schaue und explizit Werte in die Ausgabewarteschlange lege?

Antwort

0

Ich denke nicht, dass das Konditionssystem hier das Richtige ist. Es wird besser mit Fortsetzungen sein. Außerdem verwandelt der C# -Compiler die von Ihnen präsentierte Methode in ein fortsetzungsähnliches Objekt.

In Common Lisp können Sie Fortsetzungen mit Cl-Cont-Bibliothek vornehmen.

3

Plain Common Lisp unterstützt keine Coroutinen oder Abwärtskontinuitäten. Sie können nicht aus irgendeiner Berechnung herausspringen und dann wieder hineinspringen. Es gibt Bibliotheken (zum Beispiel cl-cont), die 'einige' Unterstützung für Fortsetzungen bieten.

Ich würde 'stream'-like (siehe SICP) Abstraktionen (mit FORCE und DELAY) oder etwas wie SERIES (die eine effiziente Lazy-Berechnungseinrichtung implementiert) verwenden.