以下の関数を見てください。因子のベクトルを渡し、ベクトル内の要素のいずれかが の因子であるかどうかをテストしたいと考えていx
ます。それ、どうやったら出来るの?
(defn multiple?
"Takes a seq of factors, and returns true if x is multiple of any factor."
([x & factors] (for [e m] ))
([x factor] (= 0 (rem x factor))))
以下の関数を見てください。因子のベクトルを渡し、ベクトル内の要素のいずれかが の因子であるかどうかをテストしたいと考えていx
ます。それ、どうやったら出来るの?
(defn multiple?
"Takes a seq of factors, and returns true if x is multiple of any factor."
([x & factors] (for [e m] ))
([x factor] (= 0 (rem x factor))))
を使用するだけで解決できますsome
。
=> (defn multiple? [x factors]
(some #(zero? (rem x %)) factors))
#'user/multiple?
=> (= true (multiple? 10 [3 4]))
false
=> (= true (multiple? 10 [3 4 5 6]))
true
some
最初の要因で停止します。
(defn multiple? [x & factors]
(some zero? (map #(rem x %) factors)))
また、すべてのテストが失敗した場合もsome
返します。実際に返す必要がある場合は、そこに a を入れることができます。nil
false
true?
(defn multiple? [x & factors]
(true? (some zero? (map #(rem x %) factors))))
some
短絡し、map
怠惰なのでmultiple?
、一致が見つかるとすぐに停止することに注意してください。たとえば、次のコードは sequence に対してテストします1,2,3,4,...
。
=> (apply multiple? 10 (map inc (range)))
true
明らかに、この計算はmultiple?
、シーケンス内のすべての数値に対してテストしない場合にのみ終了できます。
明示的な末尾再帰を使用して、これを試してください。
(defn multiple? [x factors]
"if any of the elements in the vector is a factor of x"
(loop [factors factors]
(cond (empty? factors) false
(zero? (rem x (first factors))) true
:else (recur (rest factors)))))
x
上記のソリューションの利点は次のとおりです。ベクトル全体を反復処理することなく、ベクトル内の要素のいずれかが係数であるかどうかが検出されるとすぐに停止します。末尾再帰を使用することで、効率的で一定のスペースで実行されます。ブール値の結果を直接返します。を返す場合を考慮する必要はありませんnil
。次のように使用します。
(multiple? 10 [3 4])
=> false
(multiple? 10 [3 4 5 6])
=> true
(このようなプロシージャを呼び出すために)ベクトルを明示的に渡す必要をなくしたい場合は、質問の場合と同じように、パラメータリストに(multiple? 10 3 4 5 6)
aを追加するだけです。&
よりクロージュリアンな方法は、より汎用的な関数を作成することです。真/偽の質問に答える代わりに、のすべての要素を返しますx
。また、シーケンスは怠惰であるため、空であるかどうかを確認したい場合は、ほぼ同じくらい効率的です。
(defn factors [x & fs]
(for [f fs :when (zero? (rem x f))] f))
(factors 5 2 3 4)
=> ()
(factors 6 2 3 4)
=> (2 3)
次に、以下を使用するだけで元の質問に答えることができますempty?
。
(empty? (factors 5 2 3 4))
=> true
(empty? (factors 6 2 3 4))
=> false