core.async 风格的持久化变量

Persisting variables in core.async style

我需要做一个大动作,很想听听你的建议。 我需要的是一个宏,它采用带有特殊“等待”形式的普通 clojure 代码。 await 表单仅包含 clojure 代码,并且应该 return 代码的 return 值。现在,我想要的是,当我 运行 这个宏生成的任何内容时,它应该在第一个“等待”表单进行评估时停止执行。

然后,它应该将到目前为止在其范围内定义的所有变量转储到数据库(我将忽略并非所有 Clojure 类型都可以序列化到 EDN 的问题,例如函数不能),以及一些标记它停在的地方。

然后,如果我想再次 运行 这段代码(可能在另一台机器上,改天)——它将从数据库中读取它的状态并从它停止的地方继续。

因此我可以有,例如:

(defexecutor my-executor  
        (let [x 7
              y (await (+ 3 x))]
             (if (await (> y x))
                  "yes"
                  "no")))

现在,当我这样做时:

(my-executor db-conn "unique-job-id")

第一次我应该得到一个特殊的 return 值,比如

:延迟

第二次应该也是这样,只有第三次才是真正的return值returned.

我的问题不是如何编写这样的执行程序,而是如何从宏中收集有关所有已声明变量的信息以便能够存储它们。后来我也想在继续执行时重新建立它们。 await 表单当然可以嵌套:)

我查看了 core.async 源代码,因为它在内部做着类似的事情,但我在那里发现的东西让我不寒而栗 - 似乎他们使用 Clojure AST 分析器来获取此信息。这真的那么复杂吗?我知道宏中的 &env 变量,但不知道如何在这种情况下使用它。任何帮助将不胜感激。

还有一件事。请不要问我为什么需要这个或者有不同的方法来解决问题 - 我想要这个特定的解决方案。

I will ignore the problem that not all Clojure types can be serialised to EDN, e.g. functions can't

如果您忽略这一点,您可以处理的 Clojure 表达式的种类将受到很大限制。函数无处不在,例如在执行 doseqfor 之类的事情时。同样,许多有趣的程序将依赖于某些 Java 对象,例如文件句柄或其他对象。

The question I have is not how to write such executor, but rather how to gather information from within the macro about all the declared variables to be able to store them.

如果你设法编写这样一个执行程序,我怀疑它的实现无论如何都需要了解局部变量。所以你可以推迟这个问题,直到你完成了你的执行器的实现——如果你可以实现你的执行器,你可能会发现它已经过时了。

I had a peek into core.async source code because it is doing a similar thing inside, but what I have found there made me shiver - it seems they employ the Clojure AST analyser to get this info. Is this really so complex?

是的,这非常麻烦。您基本上是在编写编译器。感谢您的幸运星,他们已经为您编写了分析器,您不必自己分析表达式。

I know of &env variable inside a macro, but do not have any idea how to use it in this situation.

这是简单的部分。如果愿意,您可以编写一个简单的宏,为您提供范围内的所有局部变量。这个问题之前已经被问过和回答过,例如在 .

And one more thing. Please do not ask me why I need this or that there is a different way of solving a problem - I want this specific solution.

在提问时,这通常是一种无用的态度。它承认你提出了一个 XY 问题,但仍然拒绝告诉任何人 Y 是什么。