Respuestas:
Una función puede tener múltiples firmas si las firmas difieren en aridad. Puede usar eso para proporcionar valores predeterminados.
(defn string->integer
([s] (string->integer s 10))
([s base] (Integer/parseInt s base)))
Nota que asumiendo false
y nil
son a la vez los no valores considerados, (if (nil? base) 10 base)
se podría acortar a (if base base 10)
, o adicionalmente a (or base 10)
.
recur
solo funciona en el mismo arity. si se trató anteriormente se repiten, por ejemplo:java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2, compiling:
(string->integer s 10)
)?
También puede desestructurar rest
argumentos como un mapa desde Clojure 1.2 [ ref ]. Esto le permite nombrar y proporcionar valores predeterminados para argumentos de 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
Puede ver esto en acción aquí: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (por ejemplo)
Esta solución es 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 en or
combinación conlet
(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 que los valores predeterminados dependan 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 la solución de M. 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)))
or
or
es diferente de :or
ya or
que no conoce la diferencia de nil
y false
.
Hay otro enfoque que puede considerar: funciones parciales . Podría decirse que es una forma más "funcional" y más flexible de especificar valores predeterminados para funciones.
Comience creando (si es necesario) una función que tenga los parámetros que desea proporcionar como predeterminados como los parámetros principales:
(defn string->integer [base str]
(Integer/parseInt str base))
Esto se hace porque la versión de Clojure le partial
permite proporcionar los valores "predeterminados" solo en el orden en que aparecen en la definición de la función. Una vez que los parámetros se han ordenado según lo deseado, puede crear una versión "predeterminada" de la función utilizando la partial
función:
(partial string->integer 10)
Para hacer que esta función sea invocable varias veces, puede ponerla en una variable usando def
:
(def decimal (partial string->integer 10))
(decimal "10")
;10
También puede crear un "valor predeterminado local" 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 aún puede decidir cuál será el valor predeterminado en lugar del productor de la función sin necesidad de modificar la definición de la función . Esto se ilustra en el ejemplo con el hex
que 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 alcance 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 que figuran en la parte superior de esta respuesta)
También puede consultar (fnil)
https://clojuredocs.org/clojure.core/fnil
(recur s 10)
, usando enrecur
lugar de repetir el nombre de la funciónstring->integer
. Eso facilitaría cambiar el nombre de la función en el futuro. ¿Alguien sabe alguna razón para no usarrecur
en estas situaciones?