2010-05-31 5 views
5

Я соглашусь прямо перед тем, что следующее довольно ужасное описание того, что я хочу сделать. Извиняюсь заранее. Пожалуйста, задавайте вопросы, чтобы помочь мне объяснить. :-)Общая система состояния Lisp для передачи управления

я написал ETLs (Extract, Transform, Load) на других языках, которые состоят из отдельных операций, которые выглядят примерно так:

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

Затем строка число этих операций вместе, и вызовите Диспетчер, который отвечает за вызов Операций и нажатие данных между ними.

Я пытаюсь сделать что-то подобное в Common Lisp, и хочу использовать ту же базовую структуру, то есть каждая операция определяется как нормальная функция, которая вводит список и выводит список, но лениво.

Я могу define-condition условие (have-value) использовать для поведения yield, и я могу запустить его в одном цикле, и он отлично работает. Я определения операций, точно так же, перекручивание через входы:

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

Беда в том, если я хочу, чтобы соединить вместе несколько операций, и запускать их. Моя первая попытка написать диспетчер для них выглядит примерно так:

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

Но перезагружается имеет только динамическую степень: каждая операция будет иметь те же имена рестарта. Перезапуск не является объектом Lisp, который я могу сохранить, чтобы сохранить состояние функции: это то, что вы вызываете по имени (символу) внутри блока обработчика, а не продолжение, которое вы можете сохранить для последующего использования.

Возможно ли сделать что-то вроде этого? Или мне лучше просто заставить каждую операционную функцию явно смотреть на входную очередь и явно помещать значения в очередь вывода?

ответ

0

Не думаю, что система состояния - это правильная вещь для использования здесь. Это будет лучше с продолжением. Кроме того, компилятор C# превращает метод, который вы представили, в объект, похожий на продолжение.

В Common Lisp вы можете делать продолжения с помощью библиотеки cl-cont.

3

Plain Common Lisp не поддерживает сопрограммы или нисходящие продолжения. Вы не можете выпрыгнуть из некоторых вычислений, а затем вернуться обратно. Существуют библиотеки (например, cl-cont), чтобы обеспечить «некоторую» поддержку продолжений.

Я бы использовал абстракции «stream'-like» (см. SICP) (используя FORCE и DELAY) или что-то вроде SERIES (который реализует эффективное ленивое вычислительное средство).

Смежные вопросы