Clojure 将空列表传递给函数以收集结果
我一直找不到任何关于我试图理解的东西的理论上的Clojure的例子,并希望得到一些关于它的意见 传统上,当我在命令式语言中使用递归时,我经常将空列表传递给递归函数,以便通过堆栈向下收集一些计算结果 作为Java中的一个小例子:Clojure 将空列表传递给函数以收集结果,clojure,Clojure,我一直找不到任何关于我试图理解的东西的理论上的Clojure的例子,并希望得到一些关于它的意见 传统上,当我在命令式语言中使用递归时,我经常将空列表传递给递归函数,以便通过堆栈向下收集一些计算结果 作为Java中的一个小例子: public List<Integer> results = new ArrayList<>(); private List<Integer> add(List<Integer> list, int count){
public List<Integer> results = new ArrayList<>();
private List<Integer> add(List<Integer> list, int count){
if(count > 10){
return list;
}
count = count + 1;
list.add(count);
return add(list, count);
}
将生成值0到10的列表
这是Clojure的惯用语吗
(defn t [list i]
(conj list i)
(if (<= i 10)
(recur list (inc i))))
(t '() 0)
我是否得到以下错误:
clojure.lang.Compiler$CompilerException:java.lang.ClassCastException:java.lang.Long(在模块:java.base中)不能强制转换为clojure.lang.IFn
这是Clojure的惯用语吗
(defn t [list i]
(conj list i)
(if (<= i 10)
(recur list (inc i))))
(t '() 0)
不是
在Clojure。因此,一旦调用传递列表的函数,该函数就无法修改它。所以,它不仅不地道,而且不可能
相反,在Clojure中实现所需功能的惯用方法是调用递归函数来构建一个较小的列表,并将其追加到其中
(defn my-range [n]
(if (< n 0)
[] ; empty list
(conj
(my-range (dec n)) ; recursive call to build smaller list
n)))
(定义我的范围[n]
(如果(
话虽如此,您提供的Java代码片段也不是很好;总的来说,这里有一个很好的惯例:
- 如果该方法具有void返回类型,则可能会产生副作用,并且可能会修改其中一个参数
- 如果该方法具有返回类型,那么您可能希望不修改参数
给该方法一个返回类型,同时修改一个参数,会使代码变得混乱。代码的用户无法知道是使用返回还是提供自己要修改的列表。您当然可以传入一个空列表作为结果的起点。这里应用的clojure习惯用法是函数调用
(conj list i)
返回一个添加了i的新列表,但它不会改变列表,因此在t函数中,该行不会产生任何结果。要使用该函数调用的结果,应将其作为参数传递给recur,类似于(inc i)
第二点要注意的是if语句中没有其他条件,因此一旦i的值大于10,if语句将返回nil
(defn t1 [list i]
(if (<= i 10)
(recur (conj list i) (inc i))
list))
(定义t1[列表一]
(如果(注意,conj
对于向量和列表类型的行为不同。对于向量,它会在末尾附加一个元素。对于列表,它会将元素放在其头部的前面:
user=> (conj [1 2 3] 4)
[1 2 3 4]
user=> (conj '(1 2 3) 4)
(4 1 2 3)
因此,如果任何人传递的是向量而不是列表,他或她将面临不可预测的行为。请注意,在Clojure中,向量比列表更常见(与Scheme或common list不同)
concat
功能适用于两种类型:
user=> (concat [1 2 3] [4])
(1 2 3 4)
user=> (concat '(1 2 3) [4])
(1 2 3 4)
然后,调用(conj list i)
将返回一个新的列表,而不更改前一个列表。此调用应放在其他函数调用中,例如,在recur
或let
内。否则,您将徒劳地执行。conj不会发生变异,因此您需要显式地传递其返回值。即(defn[list i](如果(
user=> (concat [1 2 3] [4])
(1 2 3 4)
user=> (concat '(1 2 3) [4])
(1 2 3 4)