了解 Clojure 中的列表理解修饰符顺序

The*_*tan 2 for-loop list-comprehension clojure

我目前正在学习 Clojure,并且一直坚持列表理解。

\n
;; /sf/answers/533764521/\n(defn gen-primes "Generates an infinite, lazy sequence of prime numbers"\n  []\n  (letfn [(reinsert [table x prime]\n            (update-in table [(+ prime x)] conj prime))\n          (primes-step [table d]\n            (if-let [factors (get table d)]\n              (recur (reduce #(reinsert %1 d %2) (dissoc table d) factors)\n                     (inc d))\n              (lazy-seq (cons d (primes-step (assoc table (* d d) (list d))\n                                             (inc d))))))]\n    (primes-step {} 2)))\n\n(defn prime-factors-not-working [x]\n  (for [y (gen-primes) \n        :when  (= (mod x y) 0) \n        :while (< y (Math/sqrt x))] \n     y))\n\n(defn prime-factors-working [x]\n  (for [y (gen-primes) \n        :while (< y (Math/sqrt x))\n        :when  (= (mod x y) 0)]\n     y))\n\n(prime-factors-working 100)\n;; \xe2\x86\xaa (2 5)\n\n(prime-factors-not-working 100)\n;; Goes into infinite loop\n
Run Code Online (Sandbox Code Playgroud)\n

(gen-primes)素数的惰性序列while工作序列和非工作序列之间的唯一区别是修饰符和的顺序when。为什么not-working执行会陷入无限循环?

\n

Eug*_*mov 5

不起作用的变体在概念上(但实际上不是)扩展为:

(loop [ys (gen-primes)
       result []]
  (if (seq ys)
    (let [y (first ys)]
      (if (= (mod x (first ys)) 0) ;; Can be replaced with `(zero? (mod x y))` BTW.
        (if (< y (Math/sqrt x))
          (recur (next ys) (conj result y))
          result)
        (recur (next ys) result)))
    result))
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,如果(mod x (first ys))不是 0,它将转到下一个数字 - 不检查它<,永远如此。

当您交换:when和时:while,上面的伪展开中的检查也会交换 - 一旦y达到 的平方根,就停止迭代x