在 Environ (Clojure) 中定义一个函数,然后在代码中使用它

Defining a function in Environ (Clojure) and then using it in code

我希望能够使用 Environ 在我的 Lieningen 项目中定义一个匿名函数。

项目文件的这一部分如下所示:

{:env {:foo (fn [s]
                (count s))}}

然后在我的代码中,我想使用那个函数。类似于:

(-> "here are a few words"
    (env :foo))

然后得到s的大小。

Environ 将简单地在 slurped 文件上调用 read-string:foo 处的值将是一个包含符号 fn 的列表,后跟一个内部带有符号 s 的向量,依此类推。即表单尚未被评估,因此您将无法调用匿名 fn.

environ.core/read-env-file

考虑一下:

(def f (read-string "(fn [s] (count s))"))

(f "test")
;; => ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn

(def evaled-f (eval (read-string "(fn [s] (count s))")))
(evaled-f "test")
;; => 4

此外,您的预期用途有点偏离。 -> 是一个宏,它将第一个参数 "thread" 放入以下形式的第一个位置。

(macroexpand '(-> "here are a few words" (env :foo)))
;; => (env "here are a few words" :foo)

我认为您正在寻找类似的东西:

(let [f (eval (env :foo))]
  (-> "here are a few words"
      f))

(env :foo) returns 列表。要从中发挥作用,您可以使用 eval 或更好的宏,如下所示:

(defmacro defn-env [fn-name env-key]
  `(def ~fn-name ~(env env-key)))

(defn-env env-fn :foo) ; => #'user/env-fn

(env-fn [1 2 3]) ; => 3

注意:如果 (env :foo) returns nil 您需要将 :plugins [[lein-environ "1.0.0"]] 添加到您的 project.clj.