當心 Clojure 的 lazy-seq
Clojure 這門語言的優雅之處自然離不開 lazy sequence, clojure.core 核心庫里面 很多函數返回值是 lazy-seq(比如 map, filter)。
lazy sequence 的好處
- 先一睹為快, 使用 lazy-cat 定義 Fibonacci 數列。
(def fib-seq (lazy-cat [0 1] (map + fib-seq (rest fib-seq))))
- 結合 map
[x y z ,,,] => [[x 0] [y 1] [z 2] ,,,] ;; (range) 返回無窮整數序列, 如果直接獲取他的值, 會內存溢出。 (defn conj-position [xs] (map #(do [%1 %2]) xs (range)))
lazy sequence 的缺陷(不能算是缺陷,是特性)
- 帶走異常
;; 定義時候不發生異常, 使用的時候發生異常, 使用的時候一定注意。 ;; 有時會拋出莫名奇妙的錯誤, 找不到出錯點。 user> (def a (for [i (range 10)] (/ 1 i))) ;; => #'user/a user> a ArithmeticException Divide by zero clojure.lang.Numbers.divide (Numbers.java:156) user>
- binding 上下文環境失效
;; map 返回 lazy sequence, 到使用時才運算, 在這個例子中,計算 ;; vs 的值的時候, 已經脫離了 (binding [*x* 7]) 的環境. user> (def ^:dynamic *x* 3) ;; => #'user/*x* user> user> (def vs (binding [*x* 7] (map #(+ *x* %) (range 10)))) ;; => #'user/vs user> vs ;; => (3 4 5 6 7 8 9 10 11 12) ;; ;; mapv 返回的不是 lazy sequence user> (def vs (binding [*x* 7] (mapv #(+ *x* %) (range 10)))) ;; => #'user/vs user> vs ;; => [7 8 9 10 11 12 13 14 15 16] ;; ;; let 綁定動態 *x* 到 lexical's variable x, 形成閉包。 user> (def vs (binding [*x* 7] (let [x *x*] (map #(+ x %) (range 10))))) ;; => #'user/vs user> vs ;; => (7 8 9 10 11 12 13 14 15 16) user>
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!