web-dev-qa-db-fra.com

Comment créer une valeur par défaut pour l'argument de fonction dans Clojure

Je viens avec ça:

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

Mais ce doit être une meilleure façon de procéder.

119
jcubic

Une fonction peut avoir plusieurs signatures si les signatures diffèrent en termes d'arité. Vous pouvez l'utiliser pour fournir des valeurs par défaut.

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

Notez qu'en supposant que false et nil sont tous deux considérés comme des non-valeurs, (if (nil? base) 10 base) pourrait être raccourci à (if base base 10), ou suite à (or base 10).

157
Brian Carper

Vous pouvez également détruire les arguments rest sous forme de carte depuis Clojure 1.2 [ ref ]. Cela vous permet de nommer et de fournir des valeurs par défaut pour les arguments de fonction:

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

Vous pouvez maintenant appeler

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

ou

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

Vous pouvez le voir en action ici: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (par exemple)

148
Matthew Gilliard

Cette solution est la plus proche de la esprit de la solution d'origine, mais légèrement plus propre

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

A modèle similaire qui peut être pratique utilise or combiné avec let

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

Bien que dans ce cas plus détaillé, il peut être utile si vous souhaitez avoir les valeurs par défaut dépendant d'autres valeurs d'entrée. Par exemple, considérez la fonction suivante:

(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

Cette approche peut facilement être étendue pour fonctionner avec arguments nommés (comme dans la solution de M. Gilliar):

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

Ou en utilisant encore plus d'une fusion:

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

Il y a une autre approche que vous voudrez peut-être envisager: partiel fonctions. Il s'agit sans doute d'un moyen plus "fonctionnel" et plus flexible de spécifier des valeurs par défaut pour les fonctions.

Commencez par créer (si nécessaire) une fonction qui a le ou les paramètres que vous souhaitez fournir par défaut comme paramètre (s) principal (s):

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

Cela est dû au fait que la version de Clojure de partial vous permet de fournir les valeurs "par défaut" uniquement dans l'ordre dans lequel elles apparaissent dans la définition de la fonction. Une fois les paramètres ordonnés comme vous le souhaitez, vous pouvez ensuite créer une version "par défaut" de la fonction en utilisant la fonction partial:

(partial string->integer 10)

Afin de rendre cette fonction appelable plusieurs fois, vous pouvez la placer dans un var en utilisant def:

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

Vous pouvez également créer un "défaut local" en utilisant let:

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

L'approche de la fonction partielle a un avantage clé sur les autres: le consommateur de la fonction peut encore décider quelle sera la valeur par défaut plutôt que le producteur du sans avoir besoin de modifier la définition de la fonction . Ceci est illustré dans l'exemple avec hex où j'ai décidé que la fonction par défaut decimal n'est pas ce que je veux.

Un autre avantage de cette approche est que vous pouvez attribuer à la fonction par défaut un nom différent (décimal, hex, etc.) qui peut être plus descriptif et/ou une portée différente (var, local). La fonction partielle peut également être mélangée avec certaines des approches ci-dessus si vous le souhaitez:

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

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

(Notez que ceci est légèrement différent de la réponse de Brian car l'ordre des paramètres a été inversé pour les raisons données en haut de cette réponse)

8
optevo

Vous pouvez également consulter (fnil)https://clojuredocs.org/clojure.core/fnil

5
celwell