这里“graph”是高阶函数,它返回一个在其范围内配置了set的函数:
(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)))
最好的方法是什么?
答案 0 :(得分: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
将使用提供的连接或绑定连接。
答案 1 :(得分: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解释的常规函数。