2010-05-31 6 views
5

Je vais admettre dès le départ que ce qui suit est une description assez terrible de ce que je veux faire. Excuses d'avance. S'il vous plaît poser des questions pour m'aider à expliquer. :-)Commun système de condition Lisp pour le transfert de contrôle

J'ai écrit (extrait ETL, Transform, Load) dans d'autres langues qui consistent en des opérations individuelles qui ont l'air quelque chose comme:

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

Ensuite, vous chaîne un certain nombre de ces opérations ensemble, et appelez The Dispatcher, qui est responsable de l'appel des opérations et de la transmission de données entre elles. J'essaie de faire quelque chose de similaire dans Common Lisp, et je veux utiliser la même structure de base, c'est-à-dire que chaque opération est définie comme une fonction normale qui introduit une liste et sort une liste, mais paresseusement.

Je peux define-condition une condition (have-value) à utiliser pour yield -comme le comportement, et je peux l'exécuter en une seule boucle, et cela fonctionne très bien. Je suis en train de définir les opérations de la même manière, une boucle à travers les entrées:

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

Le problème est si je veux enchaîner plusieurs opérations, et de les exécuter. Ma première tentative d'écriture d'un répartiteur pour ces ressemble à quelque chose comme:

(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))) 

Mais redémarre ont seulement l'étendue dynamique: chaque opération aura les mêmes noms de redémarrage. Le redémarrage n'est pas un objet Lisp que je peux stocker, pour stocker l'état d'une fonction: c'est quelque chose que vous appelez par nom (symbole) dans le bloc gestionnaire, pas une continuation que vous pouvez stocker pour une utilisation ultérieure.

Est-il possible de faire quelque chose comme je veux ici? Ou est-ce que je ferais mieux de faire en sorte que chaque fonction d'opération regarde explicitement sa file d'attente d'entrée, et place explicitement les valeurs dans la file d'attente de sortie?

Répondre

0

Je ne pense pas que ce système de condition est la bonne chose à utiliser ici. Ça va aller mieux avec les continuations. En outre, le compilateur C# transforme la méthode que vous avez présentée en un objet de type continuation.

En Common Lisp, vous pouvez faire des suites avec la bibliothèque cl-cont.

3

Le Common Lisp commun ne prend pas en charge les coroutines ou les suites descendantes. Vous ne pouvez pas sauter d'un calcul, puis revenir en arrière. Il existe des bibliothèques (par exemple cl-cont) pour fournir un certain support pour les suites. J'utiliserais des abstractions de type 'stream' (voir SICP) (en utilisant FORCE et DELAY) ou quelque chose comme SERIES (qui implémente une fonction de calcul paresseux efficace).

Questions connexes