2011-11-03 12 views
13

Escribí una función para calcular la diferencia simétrica de dos conjuntos (uno de los problemas en el sitio 4clojure). La función pasó las pruebas unitarias, pero no está tan limpia como me gustaría, dado que tengo código duplicado.¿Cómo puedo definir una función dentro de una función en Clojure y hacer referencia a esa función?

(fn [x y] (set (concat 
    (keep-indexed #(if (nil? (get y %2)) %2) x) 
    (keep-indexed #(if (nil? (get x %2)) %2) y)))) 

Obviamente yo preferiría algo así como:

(fn [x y] (set (concat (diff x y) (diff y x)))) 

donde se define la función de diferencias y de referencia "en línea", pero no sé cómo hacerlo en un bloque fn.

+2

En realidad, puede ver las respuestas de otras personas en 4clojure (una vez que haya completado la pregunta), lo que le dará una idea de cómo puede organizar sus propios intentos. –

Respuesta

21

Utilice un let o letfn:

(fn [x y] 
    (let [diff (... function body here ...)] 
    (set 
    (concat (diff x y) (diff y x))))) 
10

Una de las características que hace Clojure un ceceo (y un lenguaje funcional en general) es que funciones son las cosas de primera clase en Clojure en concreto se trata de objetos. Cuando realiza una función con (defn name [arg] ...) si crea la función y luego la almacena en una var para que pueda encontrarla más tarde desde cualquier lugar en su programa. es muy parecido a esto:

(def name (fn [arg] ...)) 

ahora el nombre contiene una función que es ampliamente accesible. Las funciones no tienen que almacenarse en vars, especialmente si solo son necesarias dentro de su función. En ese caso, tiene más sentido vincular la función a un nombre local como con la respuesta de Matt Fenwick.

(let [name (fn [agr] ...)] ...) 

la letfn macro lo hace más elegante. Lo importante es entender que las funciones son Objetos que están almacenados en cosas, y puede elegir el contenedor que se ajuste a sus necesidades.

+1

¿Por qué dijiste "Lo importante es entender que las funciones son ** Objetos ** que están almacenadas en cosas"? Decir "Objeto" puede llevar a alguien a pensar que está hablando de objetos en el sentido orientado a objetos. El "objeto" en minúscula, creo, podría ser mejor aquí. (Entiendo que Clojure se implementa en la JVM, donde muchas cosas se implementan como OO Classes and Objects, pero no creo que los nuevos Clojurianos necesariamente tengan que pensar en los detalles de implementación). –

Cuestiones relacionadas