2017-04-10 47 views
1

說,我有,我想在這兩個標準重複使用關鍵字在將它傳遞給Clojure中的宏之前,是否可以將符號解析爲其值?

(def keys [::description ::url ::mailing-list]) 

以下陣列;一個用於定義一個映射,另一個用於定義一個函數的可選參數。

(require '[clojure.spec :as spec]) 

(spec/def ::project-map 
     (spec/keys :opt-un keys)) 

(spec/def ::project-args 
     (spec/keys* :opt-un keys)) 

的問題是那麼的keyskeys*獲得通過引用的符號'keys,而不是在它的參考變量保持的解析值。

所以我的問題是:是否有可能在讀取時像普通lisp #. reader宏一樣解析鍵的值,還是必須重新定義宏以解析符號(如果它獲得符號而不是列表)文字?

回答

1

您也可以將它們包裝在另一個宏中,因爲宏負責評估它們的參數。

(defmacro def-both [name name* keys] 
    `(do (s/def ~name (s/keys :opt-un ~keys)) 
     (s/def ~name* (s/keys* :opt-un ~keys)))) 

(user/def-both ::project-map ::project-args [::description ::url ::mailing-list]) 
1

您可以構建一個半甜的解決方案與eval

(spec/def ::project-map 
    (eval `(spec/keys :opt-un ~keys))) 

(spec/def ::project-args 
    (eval `(spec/keys* :opt-un ~keys))) 

此建議通過在clojurians鬆弛mpened。

+1

作品以及使用Clojure但不幸的是不與clojurescript –

+1

嗯,這是不幸的,規範是如此馬cro重。 – Rovanion

+0

是的,我最終確實使用了宏。我希望我能擴展那個符號,儘管沒有包含在宏中。 –

0

或者你可以這樣做:

(spec/def ::project-map (spec/keys ::opt-un ~keys)) 

可能需要使用有優質的命名空間(例如,::opt-un

spec/def 

已經是一個宏)

+0

我不明白爲什麼這會起作用。由於':: opt-un'是':my-namespace/op-un'的縮寫,它不應該與命名的arg':opt-un'超過':opt-un'。如果我們查看失敗的斷言,它會檢查命名參數的值是否爲限定關鍵字,而不是命名參數本身。 [編輯]:它不起作用。看看你從規範中產生的結果。簡單地忽略':: opt-un',這就是爲什麼〜鍵的內容沒有被檢查。 – Rovanion

相關問題