Cómo crear un valor predeterminado para el argumento de la función en Clojure


Vengo con esto:

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

(string->integer "10")
(string->integer "FF" 16)

Pero debe ser una mejor manera de hacer esto.

Author: jcubic, 2010-07-09

5 answers

Una función puede tener múltiples firmas si las firmas difieren en aridad. Puede usarlo para proporcionar valores predeterminados.

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

Tenga en cuenta que suponiendo que false y nil se consideran no valores, (if (nil? base) 10 base) podría acortarse a (if base base 10), o más a (or base 10).

 145
Author: Brian Carper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-08 22:10:18

También puede desestructurar rest argumentos como un mapa desde Clojure 1.2 [ ref]. Esto le permite nombrar y proporcionar valores predeterminados para los argumentos de la función:

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

Ahora puedes llamar

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

O

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

Puedes ver esto en acción aquí: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (por ejemplo)

 141
Author: Matthew Gilliard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-28 20:49:16

Esta solución es la más cercana al espíritu de la solución original, pero marginalmente más limpia

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

Un patrón similar que puede ser útil usa or combinado con let

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

Si bien en este caso es más detallado, puede ser útil si desea tener valores predeterminados dependientes de otros valores de entrada. Por ejemplo, considere la siguiente función:

(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

Este enfoque se puede extender fácilmente para trabajar con argumentos con nombre (como en M. La solución de Gilliar) también:

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

O usando aún más de una fusión:

(defn exemplar [a & {:keys [b c] :or {b 5}}]
  (let [c (or c (* 7 b))]
    (println a b c)))
 31
Author: metasoarous,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-27 22:52:12

Hay otro enfoque que podrías considerar: funciones parciales. Estos son posiblemente una forma más" funcional " y más flexible de especificar valores predeterminados para las funciones.

Comience creando (si es necesario) una función que tenga el parámetro(s) que desea proporcionar como predeterminado(s) como parámetro(s) inicial (es):

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

Esto se hace porque la versión de Clojure de partial le permite proporcionar los valores "predeterminados" solo en el orden en que aparecen en la función definición. Una vez que los parámetros se han ordenado como desee, puede crear una versión "predeterminada"de la función utilizando la función partial:

(partial string->integer 10)

Con el fin de hacer esta función llamable varias veces se podría poner en un var usando def:

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

También puedes crear un" local default " usando let:

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

El enfoque de función parcial tiene una ventaja clave sobre los demás: el consumidor de la función todavía puede decidir cuál es el valor predeterminado value será más que el productor de la función sin necesidad de modificar la definición de la función . Esto se ilustra en el ejemplo con hex donde he decidido que la función predeterminada decimal no es lo que quiero.

Otra ventaja de este enfoque es que puede asignar a la función predeterminada un nombre diferente (decimal, hexadecimal, etc.) que puede ser más descriptivo y/o un ámbito diferente (var, local). La función parcial también se puede mezclar con algunos de los enfoques anteriores si se desea:

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

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

(Tenga en cuenta que esto es ligeramente diferente de la respuesta de Brian, ya que el orden de los parámetros se ha invertido por las razones dadas en la parte superior de esta respuesta)

 8
Author: optevo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-26 16:04:46

Usted también podría mirar en (fnil) https://clojuredocs.org/clojure.core/fnil

 5
Author: celwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-21 05:17:46