2012-02-09 18 views
6

たとえば、次のような問題Clojureでは、無名関数内で無名関数を定義することは可能ですか?

http://projecteuler.net/problem=5

を解決私は

(defn div [n] (= 0 (reduce + (map #(mod n %) (range 1 21))))) 
(take 1 (filter #(= true (div %)) (range 20 1e11 20))) 

は私がに匿名関数としての最初の行をマージしたいいくつかのゴルフの楽しみのために仮定し、次の解決策を考え出しました二行目。言語はこれをサポートしていますか?

+0

ソリューションをより効果的な方法で書き直すことができます。下の私の答えを見てください。 – viebel

答えて

17

はい、そうですが、#()リーダーマクロフォームをネストすることはできません。(fn)フォームを使用する必要があります。例えば

:外側の無名関数の引数を参照する方法はありませんので

(#(#(+ %1 %2) 1) 2) 

は、動作しません。これは、2つの引数を取る外部関数と読み取られ、内部関数は0の引数をとります。

しかし、あなたは(fn...) Sと同じことを書くことができます。

user=> (#((fn [x] (+ x %)) 1) 2) 
3 

ですから、インライン化することができます:あなたはまた、例えば、2つの無名関数のいずれかの#()フォームを使用することができます

user=> (((fn [x] (fn [y] (+ x y))) 1) 2) 
3 

divはこのように機能します(mapに渡された#()フォームを(fn)フォームに変更しなければならないことに注意してください):

#(= true (= 0 (reduce + (map (fn [x] (mod % x)) (range 1 21))))) 
+7

経験則として、 'fn'は'#() 'ではなく無名関数を定義する構文です。 '#()'は単に '#(mod%x)'のような単純な関数呼び出しの便宜のためにあり、 'fn'は多くのノイズを追加します。より長い本体 'fn'を持つ関数が望ましいでしょう。 – kotarak

0

あなたは(X2速い!)はるかに簡単かつ効率的な方法であなたのソリューションを書き換えることができ

(defn div [n] (every? #(= 0 (mod n %)) (range 1 21))) 
(take 1 (filter div (range 20 1e11 20))) 

every?は、リスト全体をトラバースではなく、停止しないため、それは、より効率的である理由は、リストの要素の1つがfalseの場合

+0

または、無理な力を完全に避けて約106倍速く解くことができます。 。 。 – ruakh

+0

確かに。しかし、私はclojure関連の改善が数学的ではないと考えていました。 – viebel

関連する問題