最初に知っておくべきことは、(ほとんどの) clojure のデータ構造は不変であり、ほとんどの関数は機能的であるということです。つまり、副作用がないということです。あなたの場合filter
、シーケンスはまったく変更されず、フィルタリングされていないアイテムのみを含む新しいシーケンスが返されます。
したがって、フィルタリングmyseq
するには、次のようにする必要があります。
(def filtered-seq (filter (fn [x] ...) myseq))
Filter は関数を繰り返し呼び出し、x
で現在フィルタリングされている項目にバインドしmyseq
ます。つまり、最初に にバインドされ{:name "Peter" :rank 2222}
、次に にバインドされます{:name "Anna" :rank 111}
。にはfiltered-seq
、関数が true を返した要素のみが含まれます。myseq
変更されません!
:rank
したがって、 222 より大きい要素のみを残す必要があります。
(filter (fn [x] (> (:rank x) 222)) myseq)
それでおしまい。filter についてもう 1 つ重要な点は、それが怠け者だということです。つまり、返されたコレクション内のアイテムは、必要な場合にのみ「実現」(または計算) されます。
仕事がうまくいくloop
ように、これを使用する必要はなく、怠惰ではありません。filter
loop
とはいえ、いくつかの問題があるため、あなたloop
は機能しません。
recur
の外loop
です。この場合、clojure は関数の先頭にループ バックします。
- 戻り値を構築する必要があり、「現在の」要素を維持する必要があります
- 終了条件を適切に確認する必要があります
コードは次のようになります (未テスト)。
(defn remove-lower [number myseq]
(loop [sq myseq res []]
(if (empty? sq)
res
(let [current (first sq)]
(if (> (:rank current) number)
(recur (rest sq) (conj res current))
(recur (rest sq) res))))))
方法に注意してください:
recur
の中にありますloop
res
戻り値をsq
含み、現在残っているシーケンスを含みます
- それぞれが次の反復のためにと
recur
の新しい値を渡しますsq
res
sq
は反復ごとに「縮小」されるため、myseq
が無限でない限り、ループは最終的に終了します。これをfilter
、無限シーケンスを問題なく処理する と比較してください。
ご覧のとおり、これは読みにくく、一般的ではなくfilter
、熱心です (怠惰ではありません)。