我会马上承认以下是对我想做的事情的非常糟糕的描述。提前道歉。请提出问题以帮助我解释。:-)
我用其他语言编写了 ETL(提取、转换、加载),其中包含看起来像这样的单个操作:
// in class CountOperation
IEnumerable<Row> Execute(IEnumerable<Row> rows) {
var count = 0;
foreach (var row in rows) {
row["record number"] = count++;
yield return row;
}
}
然后你将这些操作串在一起,并调用 Dispatcher,它负责调用 Operations 并在它们之间推送数据。
我正在尝试在 Common Lisp 中做类似的事情,并且我想使用相同的基本结构,即每个操作都被定义为一个输入列表和输出列表的普通函数,但是很懒惰。
我可以define-condition
使用条件 ( have-value
) 来使用类似 foryield
的行为,并且可以在单个循环中运行它,并且效果很好。我以相同的方式定义操作,循环输入:
(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 对象,用于存储函数的状态:它是您在处理程序块中按名称(符号)调用的东西,而不是您可以存储以供以后使用的延续。
可以在这里做我想做的事情吗?或者我最好让每个操作函数明确地查看它的输入队列,并明确地将值放在输出队列上?