2012-02-09 21 views
6

Por ejemplo, resolviendo el siguiente problemaEn Clojure, ¿es posible definir una función anónima dentro de una función anónima?

http://projecteuler.net/problem=5

me ocurrió con la siguiente solución

(defn div [n] (= 0 (reduce + (map #(mod n %) (range 1 21))))) 
(take 1 (filter #(= true (div %)) (range 20 1e11 20))) 

Supongamos que un poco de diversión golf deseo de fusionar la primera línea como una función anónima en el segunda linea. ¿El lenguaje lo admite?

+0

Puede volver a escribir su solución de una manera más efectiva. Ver mi respuesta a continuación. – viebel

Respuesta

17

Sí lo hace, pero no puede anidar los formularios #() reader-macro, tiene que utilizar el formulario (fn).

Por ejemplo:

(#(#(+ %1 %2) 1) 2) 

no funciona, porque no hay forma de referirse a los argumentos de las funciones anónimas exteriores. Esto se lee como la función externa tomando dos argumentos y la función interna tomando cero argumentos.

Pero se puede escribir lo mismo con (fn...) s:

user=> (((fn [x] (fn [y] (+ x y))) 1) 2) 
3 

También puede utilizar el formulario #() para una de las dos funciones anónimas, por ejemplo:

user=> (#((fn [x] (+ x %)) 1) 2) 
3 

Así se puede inline su función div así (tenga en cuenta que tuvimos que cambiar el formulario #() pasado a map a un formulario (fn)):

#(= true (= 0 (reduce + (map (fn [x] (mod % x)) (range 1 21))))) 
+7

Como regla general: 'fn' es la sintaxis para definir una función anónima, no' #() '. '#()' es solo una conveniencia para llamadas a funciones simples como '# (mod% x)' donde 'fn' agregaría mucho ruido. Para funciones con un cuerpo más largo, se debe preferir 'fn'. – kotarak

0

Se puede reescribir su solución de una manera mucho más simple y más eficiente (x2 más rápido!)

(defn div [n] (every? #(= 0 (mod n %)) (range 1 21))) 
(take 1 (filter div (range 20 1e11 20))) 

La razón es más eficiente porque es every? no atravesaría toda la lista, sino más bien dejar de cuando uno de los elementos de la lista es falso.

+0

O podría resolverlo aproximadamente 10⁶ veces más rápido evitando por completo la fuerza bruta. . . – ruakh

+0

De hecho. Pero estaba considerando mejoras relacionadas con 'clojure', no matemáticas. – viebel

Cuestiones relacionadas