2

这里的“graph”是高阶函数,它返回一个在其范围内设置了配置的函数:

(ns bulbs.neo4jserver.graph)

(defn out1
  "Test func that simply returns out1."
  [config]
  "out1")

(defn graph
  [config]
  (fn [func & args]
    (apply func config args)))

您创建一个图形实例,然后可以使用它来调用其他函数并自动传入配置参数:

(def g (graph {:root-uri "http://localhost"}))

(g out1)
;; => "out1"

这行得通;但是,如果您需要/将图形导入另一个命名空间,则必须在每个函数调用前加上图形命名空间:

(ns bulbs.neo4jserver.junk
  (:require [bulbs.neo4jserver.graph :as graph]))

(def g (graph/graph {:root-uri "http://localhost"}))

;; would rather do (g out1)
(g graph/out1)

相反,我想在apply函数中明确指定命名空间,这样用户就不必:

(defn graph
  [config]
  (fn [func & args]
    ;; somehow specify the graph namespace here
    (apply func config args)))

最好的方法是什么?

4

2 回答 2

3

不是您的问题的直接答案,但您使用的一般模式更常见:拥有一个保存连接参数(到数据库或另一台服务器)的有状态数据结构。大多数框架都扭转了这一点:不像你那样从保存连接参数的函数中调用你的函数,它们具有接受连接数据结构作为参数的函数。

例如,给定一个数据库连接conn,一个典型的虚构数据库库可能如下所示(注意:为清楚起见,示例已简化):

(let [conn (make-db-connection :host .... :user ....)]
  (read-from-db conn :user))

在为消息传递框架(例如 RabbitMQ)使用库时,可能如下所示:

(let [conn (make-amqp-connection :host .... :port ...)]
  (send-message conn :my-queue "hello world"))

在这两种情况下,都有一个conn数据结构用于对库函数的所有后续调用。在 OO 语言中,您将拥有一个全局的、有状态的对象来保存连接(在 Java 领域可能是一个单例)。在 Clojure 中,库通常使用with-...宏来处理此问题,该宏将特定连接绑定到内部使用的动态 var:

(with-db-connection (make-db-connection ....)
  (read-from-db :user ....))

(with-rabbit-connection (make-rabbitmq-connection ....)
  (send-message :my-queue "hello world"))

这是实现此模式的(虚构)示例。假设一个连接是一个 Java 对象:

;; a var to hold the connection
(def ^:dynamic *current-connection* nil)


(defmacro with-connection [conn & body]
  `(binding [*current-connection* ~conn]
     ~@body))

;; send-msg is using the connection object bound to
;; the *current-connetion* var
(defn send-msg [msg]
  (.sendMessage *current-connection* msg))

;; usage:
(with-connection conn
  (send-msg "hello world!"))

如果您想花哨,可以通过定义如下函数来支持这两种模式(接受连接作为参数使用绑定连接)send-msg

(defn send-msg [msg & {:keys [connection]
                       :or {connection *current-connection*}}]
  (.sendMessage connection msg))

;; usage with bound connetion:
(with-connection conn
  (send-msg "Hello World!"))

;; usage with explicit connection:
(send-msg "Hello World!"
          :connection conn)

此版本send-msg使用提供的连接,如果未指定连接,则使用绑定连接

于 2012-05-14T02:01:25.640 回答
2

您可以传递符号而不是函数并在graph函数中解析它:

(defn graph
  [config]
  (fn [func & args]
    (apply (ns-resolve 'bulbs.neo4jserver.graph func) config args)))

并称之为:

(ns bulbs.neo4jserver.junk
  (:require [bulbs.neo4jserver.graph :as graph]))

(def g (graph/graph {:root-uri "http://localhost"}))

(g 'out1)

g不再是一个高阶函数。它需要符号,而不是功能。我个人不喜欢这种方法。你为什么不喜欢指定命名空间?也许你也可以用宏做你需要的事情,但我不太了解宏。

编辑

不要这样做。使用@Ankur 和@Gert 在评论中解释的常规函数​​。

于 2012-05-13T14:41:15.050 回答