如何在clojure中返回先前计算的结果?

时间:2013-07-25 15:03:38

标签: clojure

我是clojure的新手,请原谅,如果我还没有使用正确的术语。我正在寻找一种方法,以最惯用的方式做到以下几点:

我有一个函数可以将任意给定数量的地图合并为一个,我们称之为merge-maps

现在我需要第二个调用第一个函数的函数,然后使用结果调用静态void java函数,然后返回完全相同的结果。我得到了前两件事,但我做了第三件事却失败了。由于静态void方法估计为nil,我必须以某种方式返回值,但我不明白如何:

(defn my-funky-function [& ms]
   (def merged (merge-maps ms))
   (SomeJavaClass/someStaticVoidMethod merged, "some", "other", "stuff")
   ;????? <- how do I "return" merged from here?)
)

2 个答案:

答案 0 :(得分:1)

喜欢这个

(defn my-funky-function [& ms]
   (def merged (merge-maps ms))
   (SomeJavaClass/someStaticVoidMethod merged, "some", "other", "stuff")
   merged)

注意:您应该使用let绑定,而不是使用def创建Var。

(defn my-funky-function [& ms]
   (let [merged (merge-maps ms)]
     (SomeJavaClass/someStaticVoidMethod merged, "some", "other", "stuff")
     merged))

答案 1 :(得分:1)

不需要函数,也不要在函数内部使用def,除非您明确打算“创建并实现全局变量”(def的文档字符串)。合并地图可以使用merge完成。

(doto (merge ms) (SomeJavaClass/someStaticVoidMethod "some" "other" "stuff"))

编辑:因为我的答案可能被误解为正确使用def(请参阅Leonids评论):在函数内部使用def绝不是一个好主意。我引用文档字符串来暗示使用def的全局效果,你肯定不希望在你的函数中使用def。

EDIT2:这里有关于上面这一行的更多解释:doto总是返回它的第一个参数。如果它是可变的并且后面的表达式将其修改为副作用,则返回修改后的版本。但是,如果您只想调用静态方法(可能)具有不会修改第一个参数的副作用,那么使用doto是正确的,因为您可以依赖地图的不变性。

既然你要求一般惯用法,并且想要在你的静态方法(或带副作用的函数)不希望你想要的返回值作为第一个参数时解决类似的问题,你总是可以这样做:

(doto (merge ms) (#(SomeJavaClass/someStaticMethod "Some" "other" "stuff" %)))

现在,如果由于任何原因你需要确保静态方法永远不会修改参数(如果它是一个可变的东西),使用let块也无济于事。这是因为在let-block中你将一个符号绑定到可变的东西上,你不会从符号中得到它的旧值。您需要事先创建旧值的副本,通常是通过调用它的构造函数并创建它的新实例。

repl上的示例:

(let [a (into-array [4 3 2 1]]
  (java.util.Arrays/sort a)
  a)
(first *1)
=> 1

;; now how to return the original thiing
(let [a (into-array [4 3 2 1])
      a-copy (aclone a)]
  (java.util.Arrays/sort a)
  ;; do some other ops on a, maybe invoke side-effects
  a-copy)
(first *1)
=> 4

因此,如果第一个let-block产生了你想要的结果,那么let-block可以替换为doto,这是一个帮助宏,除了为你创建let-block之外别无其他。

(doto (into-array [4 3 2 1]) java.util.Arrays/sort)
(first *1)
=> 1
(macroexpand '(doto (into-array [4 3 2 1]) java.util.Arrays/sort))
=> (let* [G__7326 (into-array [4 3 2 1])] (java.util.Arrays/sort G__7326) G__7326)

由于你没有对你的合并地图“做任何事情”,“doto”这个名字可能会有些误导,但希望我能帮你保存几行冗余代码。