Common Lisp有return-from
;当你想要从函数中提前返回时,Clojure中是否存在任何类型的return
?
答案 0 :(得分:31)
当你需要提前摆脱计算时,你需要一种方法来做到这一点,而不是纯粹主义者的论证。通常,当您减少大型集合时需要它,并且某个值表示进一步处理集合没有意义。为此,实用的Clojure提供了reduced
功能。
一个简单的例子就是,当一个数字序列相乘时,如果遇到零,你已经知道最终结果将为零,所以你不需要查看序列的其余部分。以下是使用reduced
编码的方式:
(defn product [nums]
(reduce #(if (zero? %2)
(reduced 0.0)
(* %1 %2))
1.0
nums))
reduced
将您提供的值包装在sentinel数据结构中,以便reduce
知道停止从集合中读取并立即返回reduced
值。嘿,它的功能性很强,甚至可以!
如果您使用if
将do
包裹在(println %1 %2)
中,您可以看到正在发生的事情:
user=> (product [21.0 22.0 0.0 23.0 24.0 25.0 26.0])
1.0 21.0
21.0 22.0
462.0 0.0
0.0
user=> (product [21.0 22.0 23.0 24.0 25.0 26.0])
1.0 21.0
21.0 22.0
462.0 23.0
10626.0 24.0
255024.0 25.0
6375600.0 26.0
1.657656E8
答案 1 :(得分:25)
clojure中没有任何明确的return语句。如果你愿意的话,你可以使用catch / throw组合一起破解一些东西,但是因为clojure比普通的lisp功能更强大,你实际上需要在一些嵌套块的中间提前返回的可能性比CL小很多。我能看到返回语句的唯一“好”理由是当你以一种在clojure中不惯用的方式处理可变对象时。
我不会说它永远不会有用,但我认为在Clojure中,如果你的算法需要一个return语句,那就是一个主要的代码味道。
答案 2 :(得分:17)
除非您正在编写一些非常时髦的代码,否则您希望提前返回的唯一原因是,如果满足某些条件。但是由于函数总是返回最后一个表单的结果,if
已经是这个函数 - 只需将你要返回的值放在if
的正文中,如果是{{1}},它将返回该值条件得到满足。
答案 3 :(得分:14)
我不是Clojure的专家,但似乎没有那些构造试图更具功能性。看看Stuart Halloway所说的here:
Common Lisp还支持从宏返回到“返回” 中间的一个功能。这鼓励了一种势在必行的风格 编程,Clojure不鼓励。
但是,您可以用不同的方式解决相同的问题。这是 返回示例,以功能样式重写,以便不 需要返回:
(defn pair-with-product-greater-than [n]
(take 1 (for [i (range 10) j (range 10) :when (> (* i j) n)] [i j])))
即,使用延迟序列并根据条件返回值。
答案 4 :(得分:0)
已经提供的if
选项可能是最佳选择,请注意,由于地图很简单,因此您可以始终在错误条件中返回{:error "blah"}
,并在有效条件中返回{result: x}
。
答案 5 :(得分:0)
Clojure中没有返回声明。即使您选择不使用if
或when
等流构造执行某些代码,该函数也会返回一些内容,在这些情况下nil
。唯一的出路是抛出异常,但即使这样,它也会一直冒泡并杀死你的线程,或被函数捕获 - 这将返回一个值。
答案 6 :(得分:0)
您也可以使用cond。并且在某些情况下,如果您需要评估多个表达式,请使用do。 这是一个示例:
(defn fact [x]
(cond
(< x 0) (do (println (str x " is negative number"))
(throw (IllegalArgumentException. "x should be 0 or higher")))
(<= x 1) 1
:else (* x (fact (- x 1)))))
答案 7 :(得分:-1)
简而言之,没有。如果这对你来说是一个真正的问题,那么你可以解决它 “the maybe monad”Monads具有高智力开销因此,对于许多情况,clojurians倾向于避免“如果失败的返回”风格的编程。
它有助于将功能分解为更小的功能,以减少摩擦。