2012-10-02 23 views
13

Soy nuevo en clojure, y he visto funciones anónimas escritas como:¿Hay alguna diferencia entre la sintaxis fn y # para funciones anónimas en Clojure?

(fn [x] (* x x)) 

y también les gusta:

#(* % %) 

Obviamente, el segundo es más concisa. ¿Hay alguna diferencia relevante? ¿Pueden representarse todas las funciones anónimas en cualquiera de los estilos? ¿Es uno más idiomático?

En relación con esta pregunta, no he podido determinar cómo convertir (fn [x] [x x]) a la última sintaxis. Apreciaría un puntero a la documentación que aclara esta situación.

+1

#() no tiene un do implícito. (fn [] ...) lo hace. – Bill

+0

Para profundizar en el comentario de @Bill: http://stackoverflow.com/questions/12534287/why-does-this-anonymous-function-starting-with-println-result-in-a-nullpointerex – noahlz

Respuesta

20

Las diferencias más importantes son:

  • (fn ...) se pueden anidar, #() no puede
  • puede asignar nombres a los parámetros mejor con (fn [x y] ..) o similares, en lugar de utilizar %, %2, %3 etc.
  • Puede nombrar una función con (fn ...) para uso recursivo, por ejemplo (fn fib [n] (if (<= n 1) 1 (+ (fib (- n 1)) (fib (- n 2)))))
  • Es más fácil hacer la generación/manipulación de código (fn [...] ...) desde #() es un lector de macro en lugar de un formulario Clojure normal.
  • #() es más conciso. Pero si que es una consideración importante, es probable que tenga sus prioridades mal :-)

Personalmente mi consejo sería:

  • Prefiero (fn [...] ...) en la mayoría de las circunstancias
  • Uso #() sólo para muy corto en línea funciones, por ejemplo (map #(+ 2 %) (range 10))
  • Considere también que puede ser mejor generar funciones anónimas a través de funciones de orden superior en lugar de escribirlas explícitamente, p. Ej. (comp func1 func2) o (partial func param1 param2) etc.
+1

Otra limitación que vale la pena mencionar (I no sabía si podía/debía editar su respuesta) es que 'fn' le permite nombrar su función, de modo que puedan ser referenciados dentro del cuerpo, como en:' (def hecho (fn f [x] (si (= 1 x) 1 (* x (f (dec x)))))) ' –

+0

Realmente aprecio las sugerencias' comp' y 'partial'. Me preguntaba si esos estaban presentes, habiéndolos apreciado en Haskell. –

2

Desde el docs, creo que estas son las diferencias más relevantes:

idiomáticas utilizadas sería para FNS una sola vez mapeo/filtro muy cortos y similares.

Los formularios #() no se pueden anidar.

Otra cosa es que si necesita parámetros con nombre, fn es una mejor opción. Para #() usará% o, para más parámetros, algo como% 1,% 2 y así sucesivamente (también% &).

Cuestiones relacionadas