在宏中使用功能

时间:2013-07-24 09:13:57

标签: clojure

我有这个功能正确加载我的命名空间:

(defn load-module [module-name]
    (use module-name)
)

我的“等效”宏不起作用:

(defmacro load-module-macro [module-name]
    `(
        (use '~module-name)
    )
)

我不明白这个问题。

此外,我想使用此宏来加载模块在配置中选择。在我的config.clj中,我用我的记录器模块的命名空间定义了一个包含“save-data”函数的var。然后我想在我的核心程序中加载指定的记录器。所以我可以选择直接在我的配置文件中使用记录器(磁盘上的记录器,数据库中的记录器......)。这是最好的方法吗?

编辑:

错误消息

IllegalArgumentException Don't know how to create ISeq from: java.lang.Character  clojure.lang.RT.seqFrom (RT.java:505)

2 个答案:

答案 0 :(得分:3)

不,实际上你并不想使用"使用"直接在代码中。使用会修改调用它的整个命名空间,这可能会以难以预测的方式破坏您的代码。

相反,你应该做的是: 实现日志记录接口(Protocol),编写"元构造函数"将您在config.clj中设置的任何内容调度为关键字。代码示例

    (defprotocol ILog
      (save-data [this msg] "Logs message in msg."))



    (defn create-file-log
      "Returns an object implementing ILog, opens and flushes java.io.File file."
      [file]
      (let [f ... ;; create file writer here
            ]
        (reify ILog
          (save-data [this msg] ;; Write code that writes data to file here
            ))))

     ;; create other implementations like database here or elsewhere

     (defn create-log
       "Creates a log of of the type passed in type-kw."
       [type-kw]
       (case type-kw
         :file (create-file-log "./app-log.txt")
         ;; other types
         ))

现在,您只需使用配置文件中设置的任何关键字调用create-log,并将返回的对象传递给需要进行日志记录的函数。显然,您也可以将其定义为全球对象,但我不建议这样做。

最终,您不想在配置中为所需的日志记录方法设置关键字(type-kw),还要设置其他参数,如文件名或数据库uri,以便您可以传递类似

   {:log-method :file
     :data {:fname "app-log.txt"}}
    or
   {:log-method :db
     :data {:uri "....

...到你的create-log函数,它使用这个结构来获取reify构造函数create-file-log,create-db-log等的参数。

修改 因为你不喜欢switch语句,所以这里是如何用多方法做的:

  (defmulti create-log :logging-method)
  (defmethod create-log :file
    [arg-map]
    (let [file (java.io.File. (:fname arg-map))]
      (if (.exists file)
        ... 

然后你只需在config.clj中输入一个条目

  {...
   :log {:logging-method :file
         :fname "./log-file.txt"}}

要创建新的日志记录类型,您现在要做的就是想象一个像上面那样的参数映射和create-log的构造函数方法。

答案 1 :(得分:1)

我认为你也可以使用multimethods。这是clojure的其他多态策略,可能适用于您的用例,因为您只想实现单个方法(save-data)。

;; set up a config map
(def config {:logger :db-logger)

;; set up the dispatch function to read the logger from the config map
(defmulti save-data (fn [] (:logger config))

;; define methods as required - database logging
(defmethod save-data :db-logger []
   (println "Save to database"))

;; some other logging  - can be in another file
(defmethod save-data :other-logger []
   (println "Save to other thing"))

注意:我对Clojure还不熟悉 - 所以我不确定这是否是使用多方法的“正确”方法。我见过的大多数例子都是关于参数类型的,而不是配置设置。任何专家,如果我的想法错误,请纠正我。