Clojure 在宏中使用函数

Clojure 在宏中使用函数,clojure,Clojure,我有一个正确加载我的命名空间的函数: (defn load-module [module-name] (use module-name) ) 我的“等效”宏不起作用: (defmacro load-module-macro [module-name] `( (use '~module-name) ) ) 我不明白这个问题 此外,我想使用此宏加载配置中选择的模块。在我的config.clj中,我使用包含“保存数据”函数的记录器模块的名称空间定义了一个va

我有一个正确加载我的命名空间的函数:

(defn load-module [module-name]
    (use module-name)
)
我的“等效”宏不起作用:

(defmacro load-module-macro [module-name]
    `(
        (use '~module-name)
    )
)
我不明白这个问题

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

编辑:

错误消息

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

不,事实上,您根本不想在代码中直接使用“use”。Use会修改调用它的整个名称空间,这可能会以难以预测的方式破坏代码

相反,你应该做的是: 实现一个日志接口(协议),编写一个“元构造函数”,将您在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
         ))
现在,您只需使用配置文件中设置的任何关键字调用createlog,并将返回的对象传递给需要进行日志记录的函数。显然,您也可以将其定义为全局对象,但我不建议这样做

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

   {:log-method :file
     :data {:fname "app-log.txt"}}
    or
   {:log-method :db
     :data {:uri "....
…创建日志函数,该函数使用此结构获取具体化构造函数的参数创建文件日志、创建数据库日志等

编辑: 因为您不喜欢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"}}

要创建一个新的日志类型,您现在所要做的就是想象一个类似于上面的参数映射和一个用于创建日志的构造函数方法

不,事实上,您根本不想在代码中直接使用“use”。Use会修改调用它的整个名称空间,这可能会以难以预测的方式破坏代码

相反,你应该做的是: 实现一个日志接口(协议),编写一个“元构造函数”,将您在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
         ))
现在,您只需使用配置文件中设置的任何关键字调用createlog,并将返回的对象传递给需要进行日志记录的函数。显然,您也可以将其定义为全局对象,但我不建议这样做

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

   {:log-method :file
     :data {:fname "app-log.txt"}}
    or
   {:log-method :db
     :data {:uri "....
…创建日志函数,该函数使用此结构获取具体化构造函数的参数创建文件日志、创建数据库日志等

编辑: 因为您不喜欢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"}}

要创建一个新的日志类型,您现在所要做的就是想象一个类似于上面的参数映射和一个用于创建日志的构造函数方法

我想你也可以使用多种方法来解决这个问题。这是clojure的另一个多态性策略,可能适合您的用例,因为您只希望实现一个方法(
保存数据


注意:我对Clojure还很陌生,所以我不确定这是否是使用多方法的“正确”方式。我看到的大多数示例都是在参数类型上分派的,而不是在配置设置上分派的。任何专家,如果我有错误的想法,请纠正我

我想你也可以使用多种方法来解决这个问题。这是clojure的另一个多态性策略,可能适合您的用例,因为您只希望实现一个方法(
保存数据


注意:我对Clojure还很陌生,所以我不确定这是否是使用多方法的“正确”方式。我看到的大多数示例都是在参数类型上分派的,而不是在配置设置上分派的。任何专家,如果我有错误的想法,请纠正我

(使用“~module name)
周围的宏中是否有一组额外的
()
?我总是遇到同样的问题。我编辑了最初的帖子并添加了错误消息。在
(使用“~module name)
”周围的宏中是否有一组额外的
()
?我总是遇到同样的问题。我编辑了最初的帖子并添加了错误消息。谢谢。我理解你的观点,如果这确实是最好的方式,我会这么做。但目前我认为开关的情况并不是很好。我想创建一个新的日志文件,更改配置,仅此而已,而不是在创建日志中修改开关大小写。在我的模块和加载程序之间有更好的分离。这是一个错误吗?如果你要求用不同的文件名构造一个ILog对象,请看我的最后两句话。或者我不明白你的问题…?我不确定你是否明白我的问题。对不起我的英语。我解决了这个问题,因为你的答案很好。但我觉得奇怪的是,我们必须使用一个不容易维护的元构造函数(createlog)。当我想添加或删除logger方法时,我必须修改switch case une元构造函数,而在我看来,我只想更改配置文件。好的,我们可以这样做。我将为您改进我的答案:)非常感谢!:谢谢你。我理解你的观点,如果这确实是最好的方式,我会这么做。但目前我认为开关的情况并不是很好。我想创建一个新的日志文件,更改配置,仅此而已,而不是在创建日志中修改开关大小写。在我的模块和加载程序之间有更好的分离。这是一个错误吗?如果你要求用不同的文件名构造一个ILog对象,请看我的最后两句话。或者我