ClojureScript Macro Gone Awry

时间:2016-02-02 17:36:27

标签: clojure clojurescript

目标:我正在尝试创建一个宏,它将输入视为以下内容:

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

并返回如下输出:

(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)。我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

首先,你需要什么可能有点不同。看看你想要的代码

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

你真的需要绑定var rep吗?你想要的可能就是:

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

因为不需要rep

然而,你应该考虑重读一些关于宏的文章,因为在这里你有一堆随机的qoutes和unquotes。

生成代码的宏看起来像这样:

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