[英]Clojure, implement range, why this solution doesn't work
我想實現clojure的作用域功能,為什么以下代碼不起作用?
(fn [low high]
(loop[low low
ret []]
(if(= low high)
(list ret)
(recur (inc low) (concat ret [low])))))
我在下面給出了兩個正確的實現。 您的問題是您在調用(list ret)時以另一個順序包裝了已經是列表的累加器。
(defn my-range [low high]
(loop [low low
ret []]
(if (= low high)
(seq ret)
(recur (inc low) (conj ret low)))))
(defn my-range2 [low high]
(take-while
(partial > high)
(iterate inc low)))
編輯: range
在返回的seq中不包含上限參數,將my-range2
partial
從>=
更改為>
。
您的代碼有幾個問題。
如先前的答案所指出
(list ret)
是錯誤的。 將其替換為(seq ret)
。 注意:要完全返回()
,而不是nil
表示空序列,請使用(if (seq ret) (seq ret) ())
。 零敲打可能使這不必要。 concat
在頂部。 使用conj
代替。 也,
(my-range 10 0)
永遠循環。 將=
替換=
>=
。 進行這些更改,
(defn my-range [low high]
(loop [low low, ret []]
(if (>= low high)
(if (seq ret) (seq ret) ())
(recur (inc low) (conj ret low)))))
剩下的問題是,這並不懶惰:它會在返回之前生成整個向量。 例如,
(take 5 (my-range 42 (java.lang.Integer/MAX_VALUE)))
...似乎要花很多時間,盡管您只想要五個元素。 一個簡單的懶惰版本是
(defn my-range [low high]
(lazy-seq
(if (>= low high) () (cons low (my-range (inc low) high)))))
然后
(take 5 (my-range 42 (java.lang.Integer/MAX_VALUE)))
;(42 43 44 45 46)
...是立即的。
RedDeckWins的my-range2
也一樣,而且更整潔。
編輯: range
返回列表,而不是向量,在my-range
第一個實現中將return語句更改為(if (seq ret) (seq ret) ())
。
您的代碼很好,除了(list ret)
部分。
list
函數創建具有給定元素的新列表(在您的示例中,具有單個ret
元素)。 如果要轉換順序,則應改用seq
函數 。
我也建議您不要在這里使用concat
函數 ,因為它比較懶,並且可能會導致StackOwerflowError
生成長序列。
您的其余代碼很好。
有關工作示例,請參見RedDeckWins的答案 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.