目标:我正在尝试创建一个宏,它将输入视为以下内容:
(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)。我该如何解决这个问题?
答案 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)))