将宏应用于向量

时间:2018-08-31 11:28:51

标签: clojurescript clojure.spec

想象一下,动态生成了cat的规范

[:first-name string? :surname string?]

现在我想将它们与cljs.spec.alpha/cat一起使用。

在普通的Clojure中,我可以编写一个宏,该宏将用args构造一个宏并将其赋值,对吗?但是对于ClojureScript来说,它并不容易,因为macros是编译时的野兽,而且eval也是另一回事。

将我的args向量应用于ClojureScript中的宏的解决方法是什么?

2 个答案:

答案 0 :(得分:2)

不幸的是,对于动态/数据驱动的规范来说,这并不容易,但是显然可以在将来的版本中使用。

我认为唯一的解决方法是eval,或者使用您提到的cljs.spec.alpha内部实现。

cljs.user=> (def cat-args [:x string?])
#'cljs.user/cat-args
cljs.user=> (s/def ::foo (eval (cons 's/cat cat-args)))
:cljs.user/foo
cljs.user=> (s/conform ::foo '("foo"))
{:x "foo"}

答案 1 :(得分:2)

您的规范是在编译时以符号方式生成的吗?如果是这样,也许您可​​以按照建议使用宏。

(ns foo.core)

(defmacro gen-spec []
  `'~(into '[:first-name string?] '[:surname string?]))

(defmacro apply-macro [name args-form]
  `(~name ~@(eval args-form)))

这里是使用它的示例

$ clj -m cljs.main
ClojureScript 1.10.339
cljs.user=> (require '[clojure.spec.alpha :as s])
nil
cljs.user=> (require-macros 'foo.core)
nil
cljs.user=> (foo.core/gen-spec)
[:first-name string? :surname string?]
cljs.user=> (foo.core/apply-macro s/cat (foo.core/gen-spec))
{:cljs.spec.alpha/op :cljs.spec.alpha/pcat, :ps [#object[cljs$core$string_QMARK_] #object[cljs$core$string_QMARK_]], :ret {}, :ks [:first-name :surname], :forms [cljs.core/string? cljs.core/string?], :rep+ nil}

请注意gen-spec是如何以符号形式建立规格并以引用形式返回的。