Clojure可选定义

Clojure可选定义,clojure,Clojure,在Python中,我可以执行以下操作: fast_thing_available = True try: import fast_thing except ImportError: fast_thing_available = False # snip if fast_thing_available: default = fast_thing else: default = slow_thing 有可能在Clojure做同样的事情吗? 我已尝试下一步,但失败(

在Python中,我可以执行以下操作:

fast_thing_available = True

try:
    import fast_thing
except ImportError:
    fast_thing_available = False

# snip

if fast_thing_available:
   default = fast_thing
else:
   default = slow_thing
有可能在Clojure做同样的事情吗? 我已尝试下一步,但失败(例如,仍然需要导入):


代码抛出IllegalArgumentException:即使LongAdder本身不可用,也无法解析classname:LongAdder

正如@amalloy在注释中指出的那样,时内的代码不编译。我不确定是否有办法重新编写代码,以便编译。但是,可以完全避免编译它。Clojure宏可用于从编译中排除代码

宏可以尝试导入类,并且只有在导入成功时,才能使用该类发出代码。有更简单的方法来检查类路径中是否存在类,但在编译时调用
import
是很重要的。这样代码就可以使用简单的类名(比如
LongAdder

当应用于此问题时,解决方案可能类似于下面的示例。调用
import
的代码段在
eval
等方面有点难看,但很难将非文字参数传递给
import
。如果不需要此代码是泛型的,则可以对类名进行硬编码,并简化其他一些事情

(ns sample.core)

(defmacro defn-if-class
  "If clazz is successfully imported, emits (defn name args then)
   Emits (defn name args else) otherwise."
  [clazz name args then else]
  (if (try (eval `(import ~clazz)) true (catch Exception e nil))
    `(defn ~name ~args ~then)
    `(defn ~name ~args ~else)))

(defn-if-class java.util.concurrent.atomic.LongAdder
  foo []
  ;; if class exists
  (doto (LongAdder.)
    (. increment)
    (. sum))
  ;; else
  "fallback logic in case the class is not in classpath")

(defn -main [& args]
  (println (foo)))

我应该提到的是,这个答案很大程度上受到了Jay Fields的博客文章“”和.

的启发,因此您启动了一个repl,然后键入
(import'java.util.concurrent.NotAClass)
,然后得到了一个
IllegalArgumentException
?你的代码对我来说工作正常。
ClassNotFoundException
被捕获。另一方面,您的
交换表单最好表示为:
(reset!long adder available true)
,您也可以在
时将
更简洁地表示为:
(当@long adder available…
时),并在
try
when
下,你不需要一个
do
@Josh我不同意你的评估,它按预期工作。重要的不是运行时由
import
表达式引发的ClassNotFoundException,而是编译时由
when
中的代码引发的ClassNotFoundException,无论它是否实际运行,它都会被编译。@amalloy Oops!当我运行这个示例时,我完全忘记了将类的用法放在
When
块中。谢谢你的接球!你的结论是海报想要做的是不可能的吗?不是不可能的,但它是粗俗的、艰难的,而且通常不像Clojure那样做。你基本上必须使用反射,而不是通常引用类。我在考虑宏,但我认为有更好的方法。非常感谢。
(ns sample.core)

(defmacro defn-if-class
  "If clazz is successfully imported, emits (defn name args then)
   Emits (defn name args else) otherwise."
  [clazz name args then else]
  (if (try (eval `(import ~clazz)) true (catch Exception e nil))
    `(defn ~name ~args ~then)
    `(defn ~name ~args ~else)))

(defn-if-class java.util.concurrent.atomic.LongAdder
  foo []
  ;; if class exists
  (doto (LongAdder.)
    (. increment)
    (. sum))
  ;; else
  "fallback logic in case the class is not in classpath")

(defn -main [& args]
  (println (foo)))