Skip to content

Instantly share code, notes, and snippets.

@jkugiya
Created October 3, 2014 07:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jkugiya/abb0f380d1e91bb55ded to your computer and use it in GitHub Desktop.
Save jkugiya/abb0f380d1e91bb55ded to your computer and use it in GitHub Desktop.
はじめてのClojure勉強会#5 遅延シーケンス
(defn take
"Returns a lazy sequence of the first n items in coll, or all items if
there are fewer than n."
{:added "1.0"
:static true}
[n coll]
(lazy-seq
(when (pos? n)
(when-let [s (seq coll)]
(cons (first s) (take (dec n) (rest s)))))))
; pos? => 正の数ならtrueを返す。
; (take 3 '(1 2 3 4 5 6))は↓のような感じ
; (lazy-seq (cons 1 (cons 2 (cons 3 nil))))
(defn drop
"Returns a lazy sequence of all but the first n items in coll."
{:added "1.0"
:static true}
[n coll]
(let [step (fn [n coll]
(let [s (seq coll)]
(if (and (pos? n) s)
(recur (dec n) (rest s))
s)))]
(lazy-seq (step n coll))))
; (drop 4 [1 2 3 4 5])
; (lazy-seq (rest (rest (rest (rest [1 2 3 4 5])))))
; (class (rest (rest (rest (rest [1 2 3 4 5])))))
; first, cons, restのような基本的な関数でシーケンスを作ってLazySeqでラップしてあげる
; (lazy-seq (step n coll))
; stepはすぐに評価されないので、きっとマクロ
(defmacro lazy-seq
"Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?"
{:added "1.0"}
[& body]
(list 'new 'clojure.lang.LazySeq (list* '^{:once true} fn* [] body)))
; (new clojure.lang.LazySeq (fn* [] body))
; realized?を読めとのことなので読んでみる。
(defn realized?
"Returns true if a value has been produced for a promise, delay, future or laz
y sequence."
{:added "1.3"}
[^clojure.lang.IPending x] (.isRealized x))
; https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/IPending.java
; Javaのソースにもドキュメントつけてほしいな・・・。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment