List Clojure-使用递归查找列表中的元素数

List Clojure-使用递归查找列表中的元素数,list,recursion,clojure,List,Recursion,Clojure,我已经编写了一个函数,它使用递归来查找列表中的元素数量,并且工作得很成功。但是,我并不特别喜欢我编写它的方式。现在我已经用一种方式写了,我似乎想不出另一种方式来写 我的代码如下: (def length (fn [n] (loop [i n total 0] (cond (= 0 i) total :t (recur (rest i)(inc total)))))) 对我来说,它似乎太复杂了,有人能想出另一种方法来写它进行比较吗 非常感谢您的帮助。以下是显示一些不同解

我已经编写了一个函数,它使用递归来查找列表中的元素数量,并且工作得很成功。但是,我并不特别喜欢我编写它的方式。现在我已经用一种方式写了,我似乎想不出另一种方式来写

我的代码如下:

(def length 
 (fn [n]
  (loop [i n total 0]
   (cond (= 0 i) total
     :t (recur (rest i)(inc total)))))) 
对我来说,它似乎太复杂了,有人能想出另一种方法来写它进行比较吗


非常感谢您的帮助。

以下是显示一些不同解决方案的代码。通常,您应该使用内置函数
count

(def data [:one :two :three])

(defn count-loop [data]
  (loop [cnt 0
         remaining data]
    (if (empty? remaining)
      cnt
      (recur (inc cnt) (rest remaining)))))

(defn count-recursive [remaining]
    (if (empty? remaining)
      0
      (inc (count-recursive (rest remaining)))))

(defn count-imperative [data]
  (let [cnt (atom 0)]
    (doseq [elem data]
      (swap! cnt inc))
    @cnt))

(deftest t-count
  (is (= 3 (count data)))
  (is (= 3 (count-loop data)))
  (is (= 3 (count-recursive data)))
  (is (= 3 (count-imperative data))))

下面是显示一些不同解决方案的代码。通常,您应该使用内置函数
count

(def data [:one :two :three])

(defn count-loop [data]
  (loop [cnt 0
         remaining data]
    (if (empty? remaining)
      cnt
      (recur (inc cnt) (rest remaining)))))

(defn count-recursive [remaining]
    (if (empty? remaining)
      0
      (inc (count-recursive (rest remaining)))))

(defn count-imperative [data]
  (let [cnt (atom 0)]
    (doseq [elem data]
      (swap! cnt inc))
    @cnt))

(deftest t-count
  (is (= 3 (count data)))
  (is (= 3 (count-loop data)))
  (is (= 3 (count-recursive data)))
  (is (= 3 (count-imperative data))))

下面是一个简单的递归版本:

(defn my-count [coll]
    (if (empty? coll) 
        0 
        (inc (my-count (rest coll)))))
请记住,这里不会进行任何尾部调用优化,因此对于长列表,堆栈将溢出

以下是使用
reduce
的版本:

(defn my-count [coll]
    (reduce (fn [acc x] (inc acc)) 0 coll))

下面是一个简单的递归版本:

(defn my-count [coll]
    (if (empty? coll) 
        0 
        (inc (my-count (rest coll)))))
请记住,这里不会进行任何尾部调用优化,因此对于长列表,堆栈将溢出

以下是使用
reduce
的版本:

(defn my-count [coll]
    (reduce (fn [acc x] (inc acc)) 0 coll))

为了完整起见,这里有另一个转折点

(defn my-count
  ([data]
   (my-count data 0))
  ([data counter]
   (if (empty? data)
     counter
     (recur (rest data) (inc counter)))))

为了完整起见,这里有另一个转折点

(defn my-count
  ([data]
   (my-count data 0))
  ([data counter]
   (if (empty? data)
     counter
     (recur (rest data) (inc counter)))))

这里有一个是尾部调用优化的,不依赖于
循环
。基本上与艾伦·汤普森的第一部相同,但内部功能是最好的。(而且对我来说感觉更地道。):-)


这里有一个是尾部调用优化的,不依赖于
循环
。基本上与艾伦·汤普森的第一部相同,但内部功能是最好的。(而且对我来说感觉更地道。):-)


为什么不直接使用呢?我必须使用递归使它工作,这就是为什么我一直使用循环的原因,也是为什么它变得如此复杂的原因。递归地使用count有意义吗?使用
loop recur
你只有一个循环,而不是递归。loop/recur在概念上与递归函数是一样的——这就是为什么“recur”是名称的一部分。它在JVM上以循环的形式实现,但是如果你将它移植到scheme,你将使用递归函数来实现它。@amalloy,我想应该指出scheme已经按照它的标准进行了要求,所以如果我没有误解你的“实现为递归函数”最有可能的结果是循环,因此与通过关键字的显式尾部调用相同(如
recur
is)。-除非它是自动完成的为什么不直接使用?我必须使用递归使它工作,这就是为什么我一直在使用循环,为什么它会如此复杂。递归地使用count有意义吗?使用
loop recur
你只有一个循环,而不是递归。loop/recur在概念上与递归函数是一样的——这就是为什么“recur”是名称的一部分。它在JVM上以循环的形式实现,但是如果你将它移植到scheme,你将使用递归函数来实现它。@amalloy,我想应该指出scheme已经按照它的标准进行了要求,所以如果我没有误解你的“实现为递归函数”最有可能的结果是循环,因此与通过关键字的显式尾部调用相同(如
recur
is)。-除非它是自动完成的为什么还要提到如何用原子来做呢?这是一种任何人都会反对的反模式;如果您想在其他两种好方法的基础上添加第三种方法,那么reduce就是要展示的功能。有时候,命令式/可变方法是最简单的答案(显然,对于本例来说,除了计数之外的所有方法都是多余的)。如果没有人能看到的代码是命令式的或可变的,并且不会泄露出去,那么为什么还要担心呢?如果你挖得足够深,一切都是可变的/必须的。只有当它泄漏出来时才成为问题。这是一种非常面向图灵机器的思维方式。或者你可以说,如果你挖得足够深,一切都是递归的(lambda演算)。只有当您必须在现实生活中的现代物理处理器上实际实现它时,必要的实现细节才会泄露出来。为什么还要提到如何使用atom来实现呢?这是一种任何人都会反对的反模式;如果您想在其他两种好方法的基础上添加第三种方法,那么reduce就是要展示的功能。有时候,命令式/可变方法是最简单的答案(显然,对于本例来说,除了计数之外的所有方法都是多余的)。如果没有人能看到的代码是命令式的或可变的,并且不会泄露出去,那么为什么还要担心呢?如果你挖得足够深,一切都是可变的/必须的。只有当它泄漏出来时才成为问题。这是一种非常面向图灵机器的思维方式。或者你可以说,如果你挖得足够深,一切都是递归的(lambda演算)。只有当您必须在现实生活中的现代物理处理器上实际实现它时,必要的实现细节才会泄漏出来。