Clojure:从模板生成函数

标签 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)))))

我需要能够这样称呼它:
(string-to-date "2011-02-17")

(string-to-date "2/17/2011" (using-format "M/d/yyyy"))

(string-to-date "2/17/2011" {})

第三种情况有点问题: map 不一定包含键 :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

...这将产生一个重载函数(一元和二元),二进制具有 merge就像在第一个例子中一样。

最佳答案

因此,为了更严格地定义它,您需要创建一个宏来创建转换器函数。转换器函数是具有两个参数的函数,一个参数和两个参数。转换器函数的第一个参数是要转换的对象。第二个参数是一个选项映射,它会以某种方式影响转换(就像你的例子中的格式字符串。)

可以指定默认参数映射。当使用一个参数调用时,转换器函数将使用默认参数映射。当使用两个参数调用时,转换器函数会将默认参数映射与传入的参数映射合并,以便传入的参数覆盖默认值(如果存在)。

让我们称这个宏为 def-converter。 Def 转换器将接受三个参数,第一个是要创建的函数的名称。第二个是两个参数的匿名函数,它实现了双元转换器,没有默认的参数合并。第三个参数是默认的参数映射。

像这样的事情会起作用:

(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#))))))

然后你可以像这样使用它:
(def-converter 
  string-to-date  
  (fn [to-convert conversion-params] 
    (parse-date to-convert conversion-params))
  (using-format "yyyy-MM-dd"))

但是您必须对您的辅助功能之一进行更改:
(defn- parse-date [str params] 
  (.parse (java.text.SimpleDateFormat. (:format params)) str))

这是因为宏需要足够通用来处理参数的任意映射,所以我们不能指望。可能有解决方法,但我想不出比将其推送到辅助函数(或需要传递给 def-converter 的匿名函数)更麻烦的方法。

关于Clojure:从模板生成函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5035086/

相关文章:

java - 从 Clojure 调用可变参数 Java 函数时出现问题

clojure - 了解 Clojure 绑定(bind)语法

java - 从 Clojure 持久哈希中获取未知 key

string - 如何在clojure中检查字符串是否为大写?

java - 如果存在强引用,保证返回现有对象的线程安全对象池?

loops - Clojure 循环读取一个额外的

clojure - 打ic 1.0.0-beta1错误

Clojure let 允许多个同名绑定(bind)

clojure - 如何在 Clojure 中解析和使用表?

clojure - 将 var 或 #' 应用于 Clojure 中的函数列表