2016-12-27 21 views
1
映射碼元結合宏(在一個FN)

我定義一個宏結合從字符串衍生的字符串這樣的符號:Clojure中

lein repl 
... Clojure 1.8.0 ... 
user=> (defmacro foo [s] `(def ~(symbol s) ~s)) 
#'user/foo 

它工作時在頂層援引爲預期:

user=> (foo "asdf") 
#'user/asdf 
user=> asdf 
"asdf" 

但是,當我嘗試映射,超過順序調用宏功能,宏綁定功能參數符號,而不是一個我想:

user=> (map (fn [x] (foo x)) ["qwer"]) 
(#'user/x) 
user=> x 
"qwer" 
user=> qwer 
CompilerException ... Unable to resolve symbol: qwer ... 

以下替代結合由Clojure的創建臨時符號:

user=> (map #(foo %) ["qwer"]) 
(#'user/p1__1253#) 

還裹着doall當一些我StackOverflow上研究了現有的答案的建議是行不通的。

我如何定義一個符號結合宏觀,我可以在字符串的集合(在一個函數或其他方式)的地圖?

回答

3

map是一個功能和foo是宏。由於宏擴展發生在編譯時和功能是在運行時執行的,限定一個符號結合宏,可映射(且因此在運行時展開)是不可能的。

你可以做的是這樣的:

(defn foo2 [s] 
    `(def ~(symbol s) ~s)) 

(defmacro foos [ss] 
    `(do [email protected](map foo2 ss))) 

(foos ["asdf" "qwer"]) 

asdf ;; => "asdf" 
qwer ;; => "qwer" 

現在它周圍的其他方法:宏使用函數mapfoo擴大。

2

這裏是做這件事的方式。該解決方案第一顯示foo的工作原理,然後使用帶有功能map-foo-fn然後eval的中間溶液。

最終溶液使用第二map-foo-mcr。這似乎是需要的,因爲(def ...)是一種特殊的形式。這是類似(但不相同)的「龜一路下跌」,其中使用在一個地方一個宏觀的問題,要求所有求助者也是宏,而不是功能。

(ns clj.core 
    (:require 
    [tupelo.core  :as t] )) 
(t/refer-tupelo) 

(defmacro foo 
    [arg] 
    `(def ~(symbol arg) ~arg)) 

(foo "aa") 
(spyx aa) 

(defn map-foo-fn 
    [coll] 
    (cons 'do 
    (forv [elem coll] 
     (list 'foo elem)))) 
(newline) 
(prn (map-foo-fn ["bb"])) 
(eval (map-foo-fn ["bb"])) 
(spyx bb) 

(defmacro map-foo-mcr 
    [coll] 
    `(do 
    [email protected](forv [elem coll] 
     (list 'foo elem)))) 
(newline) 
(println (macroexpand-1 '(map-foo-mcr ["cc" "dd"]))) 
(map-foo-mcr ["cc" "dd"]) 
(spyx cc) 
(spyx dd) 

結果:

aa => "aa" 

(do (foo "bb")) 
bb => "bb" 

(do (foo cc) (foo dd)) 
cc => "cc" 
dd => "dd" 

記住的是,雖然宏可以做一兩件事,功能不能(避免ARG評價),宏不能做其他的事情,功能可以。具體地,宏不能被傳遞到map等人其中需要高次函數的參數。

欲瞭解更多詳情,請參見http://www.braveclojure.com/writing-macros並搜索「宏一路到底」

注意project.clj需求

:dependencies [ 
    [tupelo "0.9.13"] 

spyx工作