ClojureScript 宏出错了

ClojureScript Macro Gone Awry

目标: 我正在尝试制作一个宏,其输入如下所示:

(cb-chan (.readFile "/path/to/file" "utf8" _))

和 returns 作为如下输出:

(go (let [c (chan 1)
          rep (.readFile "path/to/file" "utf8" (>? c)]  ; >? is a function that I defined elsewhere that jams the result of a callback into a channel
     rep
     (<! c))))

请注意,原始输入中的 _ 已被特殊回调(在别处定义)所取代。此回调将其结果塞入一个通道,然后在 go 块的末尾检索并返回。

尝试:

(defmacro cb-chan [func]
   `(cljs.core.async.macros/go 
      (let [~'c    (cljs.core.async/chan 1)]
           ~'rep  (replace (quote {~'_ (cljs-async-patterns.core/>? ~'c) }) (quote ~func))

       ~'rep
       (~'<! ~'c))))

结果: 这失败了,因为 rep 最终只是一个文字的、未计算的列表。如果我能够在倒数第二行键入 (eval rep) 而不是仅键入 rep,我的问题就会得到解决,但我不能,因为我正在使用 ClojureScript(没有 eval)。我该如何解决这个问题?

首先,您需要的可能有点不同。查看您想要的代码

(go (let [c (chan 1)
          rep (.readFile "path/to/file" "utf8" (>? c)]
      rep
      (<! c))))

你真的需要绑定一个变量rep吗?你想要的可能是这样的:

(go (let [c (chan 1)]
      (.readFile "path/to/file" "utf8" (>? c)
      (<! c))))

因为不需要rep

但是,您应该考虑重新阅读一些有关宏的文章,因为这里有乱七八糟的随机引用和取消引用。

生成代码的宏如下所示:

(defmacro cb-chan [func]
  (let [c (gensym "c")]
    `(cljs.core.async.macros/go 
       (let [~c (cljs.core.async/chan 1)
             rep# ~(replace {'_ `(cljs-async-patterns.core/>? ~c)} func)]
         rep#
         (cljs.core.async/<! ~c)))))

它将 (cb-chan (.readFile "/path/to/file" "utf8" _)) 扩展为:

(cljs.core.async.macros/go
  (let [c19307 (cljs.core.async/chan 1)
        rep__19301__auto__ (.readFile
                             "/path/to/file"
                             "utf8"
                             (cljs-async-patterns.core/>? c19307))]
    rep__19301__auto__
    (cljs.core.async/<! c19307)))

对于我的变体(没有 rep):

(defmacro cb-chan [func]
  (let [c (gensym "c")]
    `(cljs.core.async.macros/go 
       (let [~c (cljs.core.async/chan 1)]
         ~(replace {'_ `(cljs-async-patterns.core/>? ~c)} func)
         (cljs.core.async/<! ~c)))))

扩展为:

(cljs.core.async.macros/go
  (let [c19313 (cljs.core.async/chan 1)]
    (.readFile
      "/path/to/file"
      "utf8"
      (cljs-async-patterns.core/>? c19313))
    (cljs.core.async/<! c19313)))