簡體   English   中英

用於創建地圖的Clojure宏

[英]Clojure macro for creating a map

我有一個用於創建哈希映射的宏。 我應該發送一個mashup的名稱和調用函數得到的內容(在這個例子中它是一個函數xx)。

(defmacro data-for-mashup [mashup-name func]  
`(map  {} {:title :content} {~mashup-name (~@func)}))  

宏應該獲得任何mashup名稱和任何函數,這就是為什么我希望它成為一個宏。

我叫它,我希望結果看起來像這樣

{:title "Events Mashup"
 :content [{ :event-name "event name 1"
                    :performer "performer 1"
                  :date "date 1"
                       :start-time "start time 1"
                       :end-time "end time 1"}
  {:event-name "event name 2"
                       :performer "performer 2"
                      :date "date 2"
                       :start-time "start time 2"
                       :end-time "end time 2"}]}

內容標記的值實際上是地圖的矢量。

對宏的調用應該得到這樣的結果

(data-for-mashup "events" (xx))  

在REPL中我得到了這個結果

(["events" #<datamodel$xx mashup_dsl.datamodel$xx@530f0fbd>])  

macroexpand-1導致了這一點

(macroexpand-1 `(data-for-mashup "events" (xx)))  
(clojure.core/map {} {:title :content} {"events" mashup-dsl.datamodel/xx})  

(xx是我的命名空間中的一個函數。)

事實上,我希望它擴展到這個

(map {} {:title :content} {"events" (xx)})  

我究竟做錯了什么?

首先,您是否嘗試創建地圖調用或哈希映射?

map用於將其第一個arg應用於其他args的每個元素。 將{}應用於某些內容將不會生成哈希映射。 對於任何單個參數,空的hashmap將返回nil。

user> (map {} [:a :b :c])
(nil nil nil)

作為函數提供給空hashmap的兩個參數將始終返回第二個參數。 你想在這做什么?

user> ({} :a 0)
0

user> (map {} [:args :here :are-meaningless] (range))
(0 1 2)

接下來,〜@從參數中取出最高級別的嵌套。 如果要在列表中返回函數,則需要圍繞它構建一個列表。 quote(也寫為')將阻止一對parens導致函數的應用,而是構造一個列表。

user> (macroexpand-1 ''(+))
(quote (+))

user> (quote (+))
(+)

user> (defmacro data-for-mashup [mashup-name func]  
        `(map  {} {:title :content} {~mashup-name '(~@func)}))
#'user/data-for-mashup
user> (macroexpand-1 '(data-for-mashup "events" (+)))
(clojure.core/map {} {:title :content} {"events" (quote (+))})
user> (data-for-mashup "events" (+))
(["events" (+)])

這與不使用〜@相同,只是直接使用〜,但引用它返回的內容。

user> (defmacro data-for-mashup [mashup-name func]  
        `(map  {} {:title :content} {~mashup-name '~func}))
#'user/data-for-mashup
user> (macroexpand-1 '(data-for-mashup "events" (+)))
(clojure.core/map {} {:title :content} {"events" (quote (+))})
user> (data-for-mashup "events" (+))
(["events" (+)])

如果您正在嘗試構建哈希映射,我認為以下定義之一可能是您想要的:

user> (defmacro data-for-mashup [mashup-name func]  
        `(zipmap [:title :content] [~mashup-name '~func]))
#'user/data-for-mashup
user> (data-for-mashup "events" (+))
{:content (+), :title "events"}

user> (defn data-for-mashup [mashup-name val] (zipmap [:title :content] [mashup-name val]))
#'user/data-for-mashup
user> (data-for-mashup "events" (+))
{:content 0, :title "events"}

如果我理解你的問題,你可以在這里使用一個函數,而不是宏。 我強烈建議您盡可能使用功能。 它們更易於組合,更易於閱讀。

;; This mashup function is a higher-order function
;; It takes *another* function as an argument (f here is your content-getting function)
(defn data-for-mashup [mashup-name f]  
    {:title mashup-name :content (f)})

;; A sample content getting function
(defn events-content []
  [{:event-name "Great concert"}
   {:event-name "Above Average concert"}])

;; Call the data-for-mashup with the title and the content-getting function
(data-for-mashup "events" events-content)

;; Result
{:title "events"
 :content
    [{:event-name "Great concert"}
     {:event-name "Above Average concert"}]}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM