I want to use one macro to handle with seq parameter, but I don’t know how!
e.g.:
(defmacro create-table-def
[s]
`(let [ks# (keys (struct-map ~s))
sql# (map (fn [p#] (str (name p#) " varchar(20) ")) ks#)]
(str "create-table " '~s " ( "
(apply str (interleave seq# ", ")) " ) ") ))
I have multiple parameter invoke this macro, but not use map (map create-table-def ps) or reduce, what should I do to deal with.
I use a macr开发者_JS百科o because I want to know the parameter symbol.
I came up with this version that is reasonably close to your version:
(defmacro create-table-def [table-name key-val-map]
(let [sql-part1 (vector "create table "
(name table-name)
"(")
sql-pre-part2 (apply vector
(map #(str (name (first %))
" "
(second %))
key-val-map))
sql-part2 (butlast (interleave sql-pre-part2 (repeat ", ")))
sql-part3 [");"]]
(apply str (concat sql-part1 sql-part2 sql-part3))))
(create-table-def my-table {foo "varchar(20)" bar "int"})
;"create table my-table(foo varchar(20), bar int);"
And if you really need to pass in a seq you can do this:
(defmacro create-table-def2 [[name & pairs]]
`(create-table-def ~name ~(apply array-map pairs)))
(create-table-def2 [my-table foo "varchar(20)" bar "int"])
;"create table my-table(foo varchar(20), bar int);"
Or just as direct arguments:
(defmacro create-table-def3 [name & pairs]
`(create-table-def ~name ~(apply array-map pairs)))
(create-table-def3 my-table foo "varchar(20)" bar "int")
;"create table my-table(foo varchar(20), bar int);"
More directly focussed towards the solutions however, (ab)using the printed representation of a map:
(use '[clojure.contrib.string :as str-utils])
(defmacro table-def [tname & things]
(str-utils/join " "
["create-table" (name tname) "("
(str-utils/drop 1
(str-utils/chop
(print-str (apply array-map things))))
");"]))
(table-def my-table foo "varchar(20)" bar "int")
;"create-table my-table ( foo varchar(20), bar int );"
精彩评论