Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在clojure中返回先前计算的结果?_Clojure - Fatal编程技术网

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

如何在clojure中返回先前计算的结果?,clojure,Clojure,我是clojure的新手,请原谅,如果我还没有使用正确的术语。我正在寻找一种方法,以最惯用的方式执行以下操作: 我有一个函数,可以将任意给定数量的贴图合并为一个,我们称之为merge maps 现在我需要第二个函数来调用第一个函数,然后使用结果调用静态void java函数,然后返回完全相同的结果。我得到前两件事,但第三件事我做不到。由于静态void方法的evaluation为nil,因此我必须以某种方式返回该值,但我不明白如何: (defn my-funky-function [& m

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

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

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

(defn my-funky-function [& ms]
   (def merged (merge-maps ms))
   (SomeJavaClass/someStaticVoidMethod merged, "some", "other", "stuff")
   ;????? <- how do I "return" merged from here?)
)
(定义我的时髦功能[&ms]
(def合并(合并贴图ms))
(合并了SomeJavaClass/someStaticVoidMethod,“some”、“other”、“stuff”)
像这样

(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))

不需要函数,也不要在函数内部使用
def
,除非您明确打算“创建并插入一个全局变量”(docstring of
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块中,您将符号绑定到可变对象,并且无法从符号中获取其旧值。您需要事先创建旧值的副本,通常是通过调用其构造函数并创建其新实例

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块生成所需的结果,则可以将let块替换为doto,doto是一个辅助宏,它除了为您创建该let块之外,什么都不做

(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”可能有点误导,但希望我能说服您保存几行冗余代码。

IIRC对函数中最后一行的求值结果是返回值。您永远不要在函数内部使用
def
。这不仅是因为您影响了全局范围,还因为Clojure为
def
duri创建了变量把compilation@m0skit0不是,因为void方法返回nil。当然,我是指非void函数(不是方法,这不是OOP)。对全局变量使用
def
是一个非常糟糕的主意。还有很多其他方法可以做到这一点:原子、动态变量(请参阅)、refs。def
意味着每个变量只能使用一次(设置根绑定)我完全同意你的看法。你想在Dominics answer上写评论吗?我很难想象有什么理由在函数中使用def。也许是为了重置一个kitchensink式的名称空间,这个名称空间只在repl中用于开发。但我从来没有这样做过,当然也不会推荐。我引用了docstr这是为了提示def的效果,同时也为了说明使用def绑定符号与使用let-bindings不同。第一个选项不是线程安全的。如果两个对我的funky函数的调用同时发生,它们将共享一个merged值。几乎没有理由在函数中使用def。您介意删除该examp吗所以人们不会复制它?@ArthurUlfeldt我把你可以用let代替def替换为你应该用let代替def