簡體   English   中英

Clojure,實施范圍,為什么此解決方案不起作用

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM