web-dev-qa-db-ja.com

Clojureで関数引数のデフォルト値を作成する方法

私はこれを持っています:

(defn string-> integer [str&[base]] 
(Integer/parseInt str(if(nil?base)10 base)))
 
 (string-> integer "10")
(string-> integer "FF" 16)

しかし、これを行うにはより良い方法でなければなりません。

119
jcubic

シグネチャのアリティが異なる場合、関数は複数のシグネチャを持つことができます。これを使用して、デフォルト値を提供できます。

_(defn string->integer 
  ([s] (string->integer s 10))
  ([s base] (Integer/parseInt s base)))
_

falsenilが両方とも非値と見なされると仮定すると、_(if (nil? base) 10 base)_は_(if base base 10)_、または_(or base 10)_に短縮できることに注意してください。

157
Brian Carper

Clojure 1.2 [ ref ]以降、rest引数をマップとして非構造化することもできます。これにより、関数の引数に名前を付けてデフォルトを指定できます。

(defn string->integer [s & {:keys [base] :or {base 10}}]
    (Integer/parseInt s base))

今、あなたは電話することができます

(string->integer "11")
=> 11

または

(string->integer "11" :base 8)
=> 9

これは実際に動作していることがわかります: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (例)

148

このソリューションは、元のソリューションの精神に近いですが、わずかにきれいです

(defn string->integer [str & [base]]
  (Integer/parseInt str (or base 10)))

類似のパターンこれは便利ですorletと組み合わせて使用​​します

(defn string->integer [str & [base]]
  (let [base (or base 10)]
    (Integer/parseInt str base)))

この場合、より冗長ですが、デフォルトは他の入力値に依存にしたい場合に役立ちます。たとえば、次の関数を考えます。

(defn exemplar [a & [b c]]
  (let [b (or b 5)
        c (or c (* 7 b))]
    ;; or whatever yer actual code might be...
    (println a b c)))

(exemplar 3) => 3 5 35

このアプローチは、named arguments(M. Gilliarのソリューションのように)で動作するように簡単に拡張できます。

(defn exemplar [a & {:keys [b c]}]
  (let [b (or b 5)
        c (or c (* 7 b))]
    (println a b c)))

または、さらに多くの融合を使用します。

(defn exemplar [a & {:keys [b c] :or {b 5}}]
  (let [c (or c (* 7 b))]
    (println a b c)))
33
metasoarous

あなたが考慮したいかもしれない別のアプローチがあります: 部分 関数。これらはおそらく、機能のデフォルト値を指定する、より「機能的」で柔軟な方法です。

必要に応じて、主要なパラメーターとしてデフォルトとして提供したいパラメーターを持つ関数を作成することから始めます。

(defn string->integer [base str]
  (Integer/parseInt str base))

これは、Clojureのpartialバージョンでは、関数定義に表示される順序でのみ「デフォルト」値を指定できるためです。パラメータが必要に応じて順序付けされたら、partial関数を使用して関数の「デフォルト」バージョンを作成できます。

(partial string->integer 10)

この関数を複数回呼び出し可能にするには、defを使用してvarに入れます。

(def decimal (partial string->integer 10))
(decimal "10")
;10

letを使用して「ローカルデフォルト」を作成することもできます。

(let [hex (partial string->integer 16)]
  (* (hex "FF") (hex "AA")))
;43350

部分関数アプローチには、他の方法よりも1つの重要な利点があります。関数のconsumerは、producer関数の関数定義を変更する必要なし。これはhexの例で示されており、デフォルト関数decimalは私が望むものではないと判断しました。

このアプローチのもう1つの利点は、より説明的または異なるスコープ(var、local)である別の名前(10進数、16進数など)をデフォルト関数に割り当てることができることです。必要に応じて、部分関数を上記のアプローチのいくつかと混合することもできます。

(defn string->integer 
  ([s] (string->integer s 10))
  ([base s] (Integer/parseInt s base)))

(def hex (partial string->integer 16))

(この応答の上部にある理由でパラメーターの順序が逆になっているため、これはブライアンの答えとは少し異なります)

8
optevo
5
celwell