3

SICPで関数型プログラミングを学ぼうとしています。Clojureを使いたい。

Clojure は Lisp の方言ですが、私は Lisp にあまり詳しくありません。このコード スニペットは汚れていて判読できません。Lisp の方言でより効率的なコードを書くには?

そして、他の関数から複数のパラメータ関数を渡す方法は?

(defn greater [x y z]
  (if (and (>= x y) (>= x z)) 
    (if (>= y z)
      [x,y]
      [x,z]) 
    (if (and (>= y x) (>= y z)) 
      (if (>= x z)
        [y,x]
        [y,z]) 
      (if (and (>= z x) (>= z y)) 
        (if (>= y x)
          [z,y]
          [z,x])))))

(defn sum-of-squares [x y]
    (+ (* x x) (* y y)))

(defn -main
  [& args]
  (def greats (greater 2 3 4))
  (def sum (sum-of-squares greats)))
4

3 に答える 3

7

あなたは 2 つの質問をしていますが、私はそれらに逆の順序で答えようとします。

コレクションを引数として適用する

コレクションを関数の引数として使用するには、各項目が関数の位置引数であるため、関数を使用しapplyます。

(apply sum-of-squares greats) ;; => 25


可読性

読みやすさに関するより一般的な質問については、次のとおりです。

問題を一般化することで、読みやすくすることができます。あなたのコード サンプルから、問題はコレクション内の 2 つの最大数に対して平方和を実行することで構成されているように見えます。sortしたがって、最初の 2 つの項目を取得して降順でコレクションに視覚的にわかりやすくなります。

(defn greater [& numbers]
  (take 2 (sort > numbers)))

(defn sum-of-squares [x y]
  (+ (* x x) (* y y)))

その後、 を使用applyしてそれらを関数に渡すことができますsum-of-squares

(apply sum-of-squares (greater 2 3 4)) ;; => 25

心に留めておいてください: sort 関数は遅延ではありません。したがって、与えられたコレクション全体を認識し、並べ替えます。これは、一部のシナリオでパフォーマンスに影響を与える可能性があります。しかし、この場合、それは問題ではありません。


一歩先へ

sum-of-squares2 つの引数xyをコレクションに切り替えることで、複数の引数を処理するように関数をさらに一般化できます。

(defn sum-of-squares [& xs]
  (reduce + (map #(* % %) xs)))

#()上記の関数は、省略形の構文を使用して数値を 2 乗する無名関数を作成します。その関数は、コレクションmap内のすべてのアイテムに対してを使用して遅延マッピングされます。xsだから、[1 2 3]なるでしょう(1 4 9)。このreduce関数は各アイテムを受け取り、そのアイテムと+現在の合計に関数を適用して、コレクションの合計を生成します。(+は複数のパラメーターを取るため、この場合は も使用できますapply。)

スレッド化マクロの 1 つを使用してすべてをまとめると、->>非常に親しみやすくなります。(ただし、この場合、より読みやすくするためにある程度の構成可能性をトレードオフしたという議論がなされる可能性があります。)

(defn super-sum-of-squares [n numbers]
  (->> (sort > numbers)
       (take n)
       (map #(* % %))
       (reduce +)))

(super-sum-of-squares 2 [2 3 4]) ;;=> 25


于 2013-10-16T20:42:39.650 に答える
3

(defn greater [& args] (take 2 (sort > args)))

(defn -main
  [& args]
  (let [greats (greater 2 3 4)
        sum (apply sum-of-squares greats)]
    sum))

優れた clojure スタイルの鍵は、組み込みのシーケンス操作を使用することです。別のアプローチは、深くネストされた if ステートメントの代わりに、単一の cond フォームでした。

def関数本体内で使用しないでください。

関数は使用可能な結果を​​返す必要があります (プロジェクトを実行すると、-main によって返される値が出力されます)。

apply提供された関数の引数としてリストを使用します。

于 2013-10-16T20:43:04.040 に答える
1

読みやすいコードを書くには、言語が提供する関数を可能な限り使用します。 たとえば greater、次のように定義できます。

(defn greater [& args]
   (butlast (sort > args)))

sum-of-squaresからの戻り値を処理するには、greater引数の分解を使用します

(defn sum-of-squares [[x y]] 
   (+ (* x x) (* y y)))

これには、引数シーケンスの要素数がわかっている必要があります。

sum-of-squaresまたは引数として単一のシーケンスを取るように定義します

(defn sum-of-squares [args]
   (reduce + (map (fn [x] (* x x)) args)))
于 2013-10-16T20:43:34.077 に答える