我想將函數的var-args發送到宏,仍然是var-args。 這裏是我的代碼:如何將序列(var-args)擴展爲不同的項目
(defmacro test-macro
[& args]
`(println (str "count=" ~(count args) "; args=" [email protected])))
(defn test-fn-calling-macro
[& args]
(test-macro args))
的(test-macro "a" "b" "c")
輸出是什麼,我想:count=3; args=abc
的(test-fn-calling-macro "a" "b" "c")
輸出爲:count=1; args=("a" "b" "c")
因爲ARGS被作爲一個參數傳遞給宏。如何在我的函數中擴展這個參數以便用3個參數調用宏?
我想我只是缺少一個簡單的核心功能,但我無法找到它。由於
EDIT 2 - 我的「真實」的代碼,在下面EDIT部分顯示的是不使用這一技術的有效情況。
正如@布賴恩指出,宏xml-to-cass
可以用這樣的功能所取代:
(defn xml-to-cass
[zipper table key attr & path]
(doseq [v (apply zf/xml-> zipper path)] (cass/set-attr! table key attr v)))
編輯 - 下面的部分超出了我原來的問題,但任何見解是值得歡迎的
上面的代碼只是我能找到的最簡單的問題。我真正的代碼處理clj-cassandra和zip-filter。它也可能看起來過度工程,但它只是一個玩具項目,我正試圖在同一時間學習這門語言。
我想解析一些在mlb.com上找到的XML,並將找到的值插入到cassandra數據庫中。這是我的代碼和背後的想法。
步驟1 - 功能工作正常,但包含代碼重複
(ns stats.importer
(:require
[clojure.xml :as xml]
[clojure.zip :as zip]
[clojure.contrib.zip-filter.xml :as zf]
[cassandra.client :as cass]))
(def root-url "http://gd2.mlb.com/components/game/mlb/year_2010/month_05/day_01/")
(def games-table (cass/mk-cf-spec "localhost" 9160 "mlb-stats" "games"))
(defn import-game-xml-1
"Import the content of xml into cassandra"
[game-dir]
(let [url (str root-url game-dir "game.xml")
zipper (zip/xml-zip (xml/parse url))
game-id (.substring game-dir 4 (- (.length game-dir) 1))]
(doseq [v (zf/xml-> zipper (zf/attr :type))] (cass/set-attr! games-table game-id :type v))
(doseq [v (zf/xml-> zipper (zf/attr :local_game_time))] (cass/set-attr! games-table game-id :local_game_time v))
(doseq [v (zf/xml-> zipper :team [(zf/attr= :type "home")] (zf/attr :name_full))] (cass/set-attr! games-table game-id :home_team v))))
import-game-xml-1
到該參數可以是例如"gid_2010_05_01_colmlb_sfnmlb_1/"
。我刪除了「gid_」和尾部斜線,使其成爲我數據庫中ColumnFamily遊戲的關鍵。
我發現3 doseq
是很多重複(最終版本應該有3個以上)。所以在這裏使用宏代碼模板似乎很合適(如果我錯了,請糾正我)。
第2步 - 介紹了代碼模板的宏(仍然有效)
(defmacro xml-to-cass
[zipper table key attr & path]
`(doseq [v# (zf/xml-> ~zipper [email protected])] (cass/set-attr! ~table ~key ~attr v#)))
(defn import-game-xml-2
"Import the content of xml into cassandra"
[game-dir]
(let [url (str root-url game-dir "game.xml")
zipper (zip/xml-zip (xml/parse url))
game-id (.substring game-dir 4 (- (.length game-dir) 1))]
(xml-to-cass zipper games-table game-id :type (zf/attr :type))
(xml-to-cass zipper games-table game-id :local_game_time (zf/attr :local_game_time))
(xml-to-cass zipper games-table game-id :home_team :team [(zf/attr= :type "home")] (zf/attr :name_full))))
我認爲這是一個進步,但我還是看到總是在我的電話重複使用相同的3個參數來xml-to-cass
一些重複。那是我引入了一箇中間功能來照顧那些人。
第3步 - 添加一個函數來調用宏(問題就在這裏)
(defn import-game-xml-3
"Import the content of xml into cassandra"
[game-dir]
(let [url (str root-url game-dir "game.xml")
zipper (zip/xml-zip (xml/parse url))
game-id (.substring game-dir 4 (- (.length game-dir) 1))
save-game-attr (fn[key path] (xml-to-cass zipper games-table game-id key path))]
(save-game-attr :type (zf/attr :type)) ; works well because path has only one element
(save-game-attr :local_game_time (zf/attr :local_game_time))
(save-game-attr :home :team [(zf/attr= :type "home"] (zf/attr :name_full))))) ; FIXME this final line doesn't work
ps:我不在我的REPL,所以如果這是壞的請編輯(或評論,我會修復,當我回家) – 2011-01-13 01:25:27
謝謝。我試過這段代碼,但是我得到一個`ClassCastException:clojure.lang.ArraySeq不能轉換爲clojure.lang.IFn`。任何想法爲什麼?我確實會對我的問題有一個直接的答案,但看起來非常複雜。我編輯了我的問題以提供關於我的「真實」代碼的所有細節。也許它可以幫助。非常感謝。 – Damien 2011-01-13 04:11:24