Clojure caret como un símbolo?
(2)
Me parece que la respuesta a su pregunta es, desafortunadamente, no. En Clojure, no puedes nombrar una función ^
.
He intentado lo siguiente en el REPL:
user=> (println /^)
^
nil
Esto parece implicar que puedes escapar del quilate ( ^
) con una barra invertida. Sin embargo, si trato de declarar una función usando /^
como nombre, aparece un mensaje de error:
user=> (defn /^ [n e] (cond (= e 0) 1 :else (* n (/^ n (- e 1)))))
IllegalArgumentException First argument to defn must be a symbol
clojure.core/defn (core.clj:277)
El mismo código funciona con un nombre de texto regular:
user=> (defn exp [n e] (cond (= e 0) 1 :else (* n (exp n (- e 1)))))
#''user/exp
user=> (exp 3 3)
27
¡Me encantaría que alguien con mejor Clojure-fu que el mío pudiera demostrar que estoy equivocado! :)
Así que pensé que sería una buena idea nombrar una función que calcula el exponencial ^
, pero parece que el caret realmente hace algo especial, ya que el REPL de Clojure genera un error al evaluar ''^
. La mayoría de las búsquedas en Google me dieron this , así que me preguntaba cuál es el uso real del caret en Clojure.
(Además, ¿sería posible, después de todo, nombrar una función ^
?)
^
es "el metacarácter", le dice al lector que agregue el símbolo que comienza con ^
como metadatos al siguiente símbolo (siempre que sea algo que implemente IMetas)
user=> (def x ^:IamMeta [1 2 3])
#''user/x
user=> x
[1 2 3]
user=> (meta x)
{:tag :IamMeta}
user=>
Puede aprender mucho sobre cómo funciona el clojure bajo el capó mirando el meta
de las cosas, por ejemplo, las funciones:
user=> (meta foo)
{:ns #<Namespace user>,
:name foo, :file "NO_SOURCE_PATH",
:line 5, :arglists ([s])}
Esto se usa muy a menudo para sugerencias de tipo.
(defn foo [^String s] (.charAt s 1))
por lo general, es una buena idea activar las advertencias de reflexión (set! *warn-on-reflection* true)
y luego agregar sugerencias tipográficas hasta que desaparezcan las advertencias. sin estos, Clojure buscará el tipo de operandos de la función en tiempo de ejecución, lo que le ahorra la molestia de tener problemas con los tipos, aunque a un costo leve.
PD: Mi próximo personaje de lector favorito es el número de "envío", vale la pena aprenderlo a continuación :)
PPS: esto es diferente en clojure 1.2.x vs clojure 1.3.x en Clojure 1.2.1 los metadatos no se componen cuando se usa el meta-carácter:
user=> (def foo ^:foo ^:bar [1 2 3])
#''user/foo
user=> (meta foo)
{:tag :foo}
y en 1.3 "hace lo correcto" y también las palabras clave son opciones en lugar de "etiquetas":
user=> (def foo ^:foo ^:bar [1 2 3])
#''user/foo
user=> (meta foo)
{:foo true, :bar true}