Clojure:从模板生成函数

Kon*_*rus 6 clojure

我有一个通用转换库的以下代码:

(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在第一个例子中二进制具有相同的功能.

mbl*_*inn 5

因此,为了更严格地定义它,您需要创建一个创建转换器函数的宏.转换器函数是具有两个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的匿名函数).