如何从函数列表和值构造函数?

时间:2014-03-31 15:00:51

标签: function macros clojure

我试图用一个已经评估过的函数和一系列其他函数的结果来构建一个函数。如果我部分构造它它工作正常,但每次我尝试构建整个事情它失败。

(defn play [] 
    (let [eval1 (eval '(+ 1 1))]
        (eval `(->> ~eval1 (+ 5) (- 2) (* 7)))
    )
)

这失败了:

(defn play []
    (let [eval1 (eval '(+ 1 1))
          eval2 '((+ 5) (- 2) (* 7))]
        (eval (cons (cons eval1 eval2) ->>))
     )
)

我已经尝试了很多其他的方法来把它放在一起,我认为这归结为我不太了解clojure的这个方面。什么是解决这个问题的最佳方法?谢谢!

3 个答案:

答案 0 :(得分:4)

You generally don't want to use eval。但是,也许这次你做了,无论出于何种原因(理解Clojure的读者是一个正当理由)。所以答案取决于你对“这个问题”的意思。

第1部分 - 使用eval

一个。韦伯的answer完全没问题。如果您给出的示例只是为了让您了解Clojure读者的工作原理,那么我的其余部分可能与您无关。

第2部分 - 没有评估

如果“此问题”是指从函数列表和值构造函数,则不需要eval。将(eval '(+ 1 1))替换为(+ 1 1)。然后,因为您需要一个功能列表,您可以使用#(+ 5 %)等或(partial + 5)等,并将它们存储在列表中。

->>是一个线程宏。这意味着它在编译时执行,以转换其整个S表达式。但是在你失败的代码中,它在编译时没有S表达式 - 你会尝试在运行时通过cons在另一个上创建它的S表达式列表。

您可以编写另一个宏来执行此操作。但总的来说,当我遇到将函数列表应用于初始值的问题时,我使用reduce

(defn play []
    (let [eval1 (+ 1 1)
          eval2 (list #(+ 5 %) #(- 2 %) #(* 7 %))]
        (reduce #(%2 %) eval1 eval2)))

事实上,在我的代码中经常出现这种情况,我的大部分项目都在core.clj中有这个:

(defn freduce
   "Given an initial input and a collection of functions (f1,..,fn),
   This is logically equivalent to ((comp fn ... f1) input)."
   [in fs]
   (reduce #(%2 %) in fs))

最后,如果你想构建一个函数而不是它的评估,那么用fn包装返回值:

(defn play []
    (let [in (+ 1 1)
          fs (list #(+ 5 %) #(- 2 %) #(* 7 %))]
        (fn [] (freduce in fs))))

user=> ((play))
-35

答案 1 :(得分:1)

您的第二个play手头的两个问题是(1)您没有引用->>因此Clojure会抱怨"获取宏的价值" ,你想要做符号操作; (2)你以错误的顺序将cons列在一起。

尝试

(defn play []
  (let [eval1 (eval '(+ 1 1))
        eval2 '((+ 5) (- 2) (* 7))]
    (eval (cons '->> (cons eval1 eval2)))))

要考虑的其他事项是使用普通函数或宏,使用语法引用来捕获名称空间,使用list*而不是cons

答案 2 :(得分:0)

(+ 1 1)不是函数,'((+ 5) (- 2) (* 7))不是函数列表。

如果你有一个功能列表,请说

(def fns (list (partial + 5) (fn [x] (- 2 x)) #(* 7 %)))

您可以实现"从功能列表构建功能的目标"

(def master-fn (->> fns reverse (apply comp)))

然后你可以用&#34来调用它;一个已经评估的函数的结果[call]":

(master-fn (+ 1 1))
;; => -35