применять макросы к вектору - PullRequest
0 голосов
/ 31 августа 2018

Представьте, что у вас есть динамически сгенерированные спецификации для cat

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

Теперь я хочу использовать их с cljs.spec.alpha/cat.

В простом Clojure я могу написать макрос, который будет содержать макрос с аргументами и оценивать его, верно? Но для ClojureScript это не так просто, потому что macros - звери во время компиляции, а также eval - тоже немного другое.

Какие есть обходные пути для применения моего вектора аргументов к макросу в ClojureScript?

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

Ваша спецификация генерируется символически во время компиляции? Если это так, возможно, вы могли бы использовать макрос, как вы предлагали.

(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 символически создает спецификацию и возвращает ее в кавычках.

0 голосов
/ 31 августа 2018

К сожалению, для динамических спецификаций и спецификаций, управляемых данными, это нелегко, но, видимо, над этим работает в будущем выпуске.

Я думаю, что единственные обходные пути - 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"}
...