我有一个通用转换库的以下代码:
(defn using-format [format] {:format format})
(defn- parse-date [str format]
(.parse (java.text.SimpleDateFormat. format) str))
(defn string-to-date
([str]
(string-to-date str (using-format "yyyy-MM-dd")))
([str conversion-params]
(parse-date str (:format (merge (using-format "yyyy-MM-dd") conversion-params)))))
Run Code Online (Sandbox Code Playgroud)
我需要能够像这样调用它:
(string-to-date "2011-02-17")
(string-to-date "2/17/2011" (using-format "M/d/yyyy"))
(string-to-date "2/17/2011" {})
Run Code Online (Sandbox Code Playgroud)
第三种情况有些问题:地图不一定包含:format对功能至关重要的键.这就是merge默认值的原因.
我需要有十几个类似的函数用于所有其他类型之间的转换.是否有一种更优雅的方式,不需要我merge在每个功能中复制粘贴,使用等?
理想情况下,寻找这样的东西(宏?):
(defn string-to-date
(wrap
(fn [str conversion-params]
(parse-date str (:format conversion-params))) ; implementation
{:format "yyyy-MM-dd"})) ; default conversion-params
Run Code Online (Sandbox Code Playgroud)
...这将产生一个重载函数(一元和二元),merge在第一个例子中二进制具有相同的功能.
因此,为了更严格地定义它,您需要创建一个创建转换器函数的宏.转换器函数是具有两个arities,一个参数和两个参数的函数.转换器函数的第一个参数是要转换的对象.第二个参数是选项映射,它会以某种方式影响转换(如示例中的格式字符串).
可以指定默认参数映射.使用一个参数调用时,转换器函数将使用默认参数映射.当使用两个参数调用时,转换器函数将默认参数映射与传入的参数映射合并,以便传入的参数覆盖默认值(如果存在).
我们称之为宏定义转换器.Def转换器将采用三个参数,第一个是要创建的函数的名称.第二个是两个参数的匿名函数,它实现了两个转换器,没有默认的parm合并.第三个参数是默认的parm映射.
这样的东西会起作用:
(defmacro def-converter [converter-name converter-fn default-params]
(defn ~converter-name
([to-convert#]
(let [default-params# ~(eval default-params)]
(~converter-fn to-convert# default-params#)))
([to-convert# params#]
(let [default-params# ~(eval default-params)]
(~converter-fn to-convert# (merge default-params# params#))))))
Run Code Online (Sandbox Code Playgroud)
然后你就可以使用它:
(def-converter
string-to-date
(fn [to-convert conversion-params]
(parse-date to-convert conversion-params))
(using-format "yyyy-MM-dd"))
Run Code Online (Sandbox Code Playgroud)
但是你必须改变你的一个辅助函数:
(defn- parse-date [str params]
(.parse (java.text.SimpleDateFormat. (:format params)) str))
Run Code Online (Sandbox Code Playgroud)
这是因为宏需要足够通用以处理任意参数映射,因此我们不能指望.可能存在各种方法,但是我不能想到一个非常简单的方法,而不仅仅是将其推送到辅助函数(或者需要传递给def-converter的匿名函数).