2012-04-27 9 views
1

私はClojureを習得しようとしていますので、オイラーのプロジェクトの課題を解決するには良い方法があると思いました。最初の課題は、3または5で割り切れる1000以下の数を合計することです。Clojure:フィルタはどのようにロジックと相互作用しますか?

私の元のコードはでした:

(defn div3 [input-no] (zero? (mod input-no 3))) 
(defn div5 [input-no] (zero? (mod input-no 5))) 
(reduce + (filter (or div3 div5) (range 1 1000))) 

しかし、それは動作しませんでした、そしてそれはフィルタがちょうど5

で割り切れるものを3で割り切れる数のリストを返し、ないだろうと判明

コードを次のように変更しました:

(defn div3or5 [input-no] (or (div3 input-no) (div5 input-no))) 
(reduce + (filter div3or5 (range 1 1000))) 

正しい結果が得られましたが、元のコードが機能しなかった理由はわかりません。

誰もがこれにいくつかの光を当てることができますか?

+0

Clojureを学ぶ別の方法は、あなたが別の言語で行うプロジェクトを見つけることです。私にとってはCやr Pythonで実装されていて、Clojureに書きます。私にとっては、.csv入力を受け取り、.csv入力データからHTTPリクエストを作成して送信し、結果を取得し、それに基づいて別の.csvファイルを書き出していました。 – octopusgrabbus

+0

Clojure http://www.4clojure.com/(意図していないことは意図していません)は良いですが、Webインターフェイスはとても簡単です! – huon

+0

これはちょうど間違いだった(これは大丈夫です - 批判は意図されていません)か、あなたが入力した内容が意味をなさない言語があるかどうか不思議です。他の場所でその行動を見るので、述語を組み合わせることを期待していましたか?もしそうなら、どこ?ありがとう... –

答えて

3

=> (or div3 div5) 
#<user$div3 [email protected]> 

つまり、orは(そしてあなたが記述行動を与え、使用しているfilter)機能div3に評価しています。

orの理由は、最初の偽の引数(すなわち、nilまたはfalseではない最初の引数)を返します。この場合、引数は2つの関数オブジェクトであり、関数オブジェクトはnilまたはfalseではありません。

別の言い方をすると、orは機能自体で起こっているのであり、機能の結果ではありません。 Paulが言ったように、無名関数を使って、orを関数自体ではなく結果に作用させることができます。

4

実行中の問題は、filterは、最初の引数として述語(入力を受け取り、真または偽を返す関数)が必要であるということです。しかし、div3div5は関数ですが、それらを単にorと組み合わせることはできません。 1つの引数をとり、これをdiv3div5の両方に送り、orと両方の結果を呼び出す新しい関数を作成する必要があります。

幸い、これはClojureの中で行うのは簡単で、

#()を試みることは、関数のインラインを定義するための省略形です(またラムダと呼ばれる)と、あなたは、第二に%1との最初の引数に取得することができます%2と続きます。引数が1つしかない場合は%1see this question%を使用できます。

また#()が はこのようになりますfnフォームのためだけ糖衣構文であることを理解することもできます。(fn [arg1 arg2 ... & restArgs] (forms))#()にはいくつかの制限があります(たとえば、ネストすることはできません)。あなたはちょうどあなたが何が起こっているかを見ることができますREPLで(or div3 div5)を評価する場合

+1

Clojure 1.3では '(filter(some-fn div3 div5)(range 1 1000))'も使用できます。 –

+0

申し訳ありません - あなたの答えは参考になった、他の答えのちょうど最後の段落がそれを釘付けにした。 – Peter

+0

@Peter心配しないで、私はdbauppの答え​​の最後の段落が頭に釘を打つことに同意します。 clojureをお楽しみください! – Paul

関連する問題