...可変データを使った命令型プログラミングが私の脳に深く刻み込まれているだけかもしれませんが、Clojure でデータのベクトルを構築するコードは冗長で扱いにくく、複雑だと感じています。もっと良い方法があるはずです!
Ruby では次のようなコードを書くかもしれません:
results = []
a_collection.each do |x|
x.nested_collection.each do |y|
next if some_condition_holds
results << y
end
end
Clojure では、おそらく次の (恐ろしい) コードのような再帰関数を使用する以外に、これを行うためのより良い方法は知りません。
; NEWBIE ALERT! NEWBIE ALERT!
(loop [results []
remaining a_collection]
(if (empty? remaining)
results
(recur
(loop [results results
nested (nested_collection (first remaining))]
(if (empty? nested)
results
(if (some_condition_holds)
(recur results (rest nested))
(recur (conj results (first nested)) (rest nested)))))
(rest remaining))))
可変データと反復ループがなければ、コレクションを構築するには再帰を使用する必要があります。このような再帰関数にはそれぞれ(empty?)
ガード句などが必要です。全体があまりにも反復的であるため、叫びたくなります。
単純なケースではmap
これで十分ですが、ネストのレベルが複数あり、各レベルで反復をスキップする必要がある条件が存在するケースを考えています。
Common Lisp ではloop
、マクロ または を使用する場合がありますmapcan
。Clojure には のようなものはありませんかmapcan
?
ベストアンサー1
オプションの見た目が優れていると思う順に並べると次のようになります。
(for [x coll,
y (nested-collection x)
:when (not (some-condition-holds y))]
y)
あるいは、次の構文を使用する代わりにmap
、 やなどの関数を使用して構築することもできます。mapcat
for
(mapcat (fn [x]
(remove some-condition-holds
(nested-collection x)))
coll)
本当に興味がある場合は、部分関数の適用と合成を使用して構築することもできます。
(mapcat (comp (partial remove some-condition-holds)
nested-collection)
coll)
この 3 番目のスタイルは Clojure ではあまり読みやすくありませんが、他の言語では同等のコードが非常に読みやすいです。たとえば Haskell では次のようになります。
coll >>= (filter (not . someConditionHolds) . nestedCollection)