命名空间foo
定义了一组根据算术运算符定义的函数。这些是标量算术运算符或矩阵算术运算符,具体取决于foo
require
是scalar-arithmetic
还是matrix-arithmetic
命名空间。 (foo.cljc中没有很多代码,但复制它就足够了。我知道core.matrix - 这是matrix-arithmetic
定义的 - 可以处理raw标量,但在这种情况下,它比Clojure的内置算法慢很多,foo
函数的速度对我的应用程序来说很重要。)
命名空间bar-s
需要标量算术。命名空间bar-m
需要矩阵运算。两个名称空间都需要在名称空间foo
中定义的函数,但bar-s
需要在标量版本中使用这些函数,而bar-m
需要它们的矩阵形式。我们可以假设我只会在同一会话中加载bar-m
和bar-s
中的一个。 (如果我不需要这个假设,那很好,但我可以忍受它。)
我正在尝试找出bar-s
或bar-m
指定要加载的foo
版本的最佳方式,即如何强制foo
加载scalar-arithmetic
命名空间,或加载matrix-arithmetic
命名空间。 (或者:如果有一种更好,非常不同的方式来完成我想要做的事情,我很乐意重新考虑它。)
目前,这就是我正在做的事情。它似乎工作:我有另一个命名空间config
,我在其中定义一个包含布尔值的原子。在bar-s
或bar-m
中,我将此原子重置为一个值,该值将选择我想要的算术实现,然后我require
foo
。 foo
检查原子,然后require
scalar-arithmetic
或matrix-arithmetic
,具体取决于原子。
这可能是做我想要的最好的方法,但这是一种奇怪的方法,我想知道是否有更好的方法。我想如果我只是在会话开始时重置原子,我就不会有问题,但是我担心会有一些我不知道的问题。
这是设置的玩具版本:
(ns scalar-arithmetic)
(defmacro m* [x y] `(* ~x ~y))
;; Using (def m* *) instead would lose Clojure's special optimizations for *
(defmacro inv [x] `(/ 1.0 ~x))
;;;;;;;;;;;;;;;;;
(ns matrix-arithmetic
(:require [clojure.core.matrix :as mx]))
(def m* mx/mmul) ; matrix multiplication
(def inv mx/inverse) ; matrix inverse
;;;;;;;;;;;;;;;;;
(ns foo
(require [config]))
(if @config/use-core-matrix
(require '[matrix-arithmetic :refer [m* inv]])
(require '[scalar-arithmetic :refer [m* inv]]))
(defn fooey [r s] (m* r (inv s))) ; could have either scalar or matrix meaning
;; The next two namespaces would not both be loaded in the same session.
;;;;;;;;;;;;;;;;;
(ns bar-s
(require [config]))
(reset! config/use-core-matrix true)
(require '[foo])
;;;;;;;;;;;;;;;;;
(ns bar-m
(require [foo])) ;; default value of use-core-matrix is false, so this is enough.