2010-05-23 9 views
30

No puedo usar funciones lógicas en un rango de booleanos en Clojure (1.2). Ninguno de los siguientes trabajos debido a las funciones lógicas siendo macros:"reducir" o "aplicar" usando funciones lógicas en Clojure

(reduce and [... sequence of bools ...]) 
(apply or [... sequence of bools ...]) 

El mensaje de error dice que "no puedo tomar valor de una macro: #'clojure.core/and". ¿Cómo aplicar estas funciones lógicas (macros) sin escribir código repetitivo?

Respuesta

50

No utilice every? y some en su lugar.

+0

Exactamente lo que estaba buscando. –

+6

Enlaces a documentos, ['every?'] (Http://clojuredocs.org/clojure_core/clojure.core/every_q) y ['some'] (http://clojuredocs.org/clojure_core/clojure.core/some) –

+0

'some' no funciona muy bien para' or' ya que devuelve 'nil' si la expresión debe evaluar' false'. Usar '# (some? (Some true?%))' O '# (not (every? False?%))' No agrega mucho al legibilidad imo y ambos no funcionan muy bien con thread-macros que requieren paréntesis extra alrededor la lambda. Además 'some?' Solo ha estado disponible desde v1.6. –

14

respuesta de Michal ya está en el clavo, pero el siguiente enfoque alternativo puede ser útil en situaciones similares cada vez que desee utilizar una macro como una función:

(reduce #(and %1 %2) [... sequence of bools ...])

Básicamente que acaba de envolver la macro en una función anónima.

Hay un par de buenas razones para considerar este enfoque:

  • Hay situaciones donde no existe una función útil como some o every?
  • Es posible obtener un mejor rendimiento (reducción es probable que los beneficios desde unas muy buenas optimizaciones en el futuro, por ejemplo, se aplican directamente a la función de un vector en vez de convertir el vector en una secuencia)
+0

Esto bien puede dar * peor * rendimiento. 'reduce' * calcula * la respuesta de la secuencia completa. '¿cada?'devuelve' false' tan pronto como encuentre un elemento falso. En mi máquina, '(reduce # (y% 1% 2) (cons nil (rango 100000000)))' toma algunos segundos, mientras que '(cada? Identidad (cons nil (rango 100000000)))' regresa instantáneamente. Formalmente, 'reduce' es tiempo lineal, mientras que, dada la probabilidad de que exista un elemento falso,' every' es tiempo constante * en promedio *, aunque lineal en el peor de los casos. – Thumbnail

+1

@Thumbnail - muy cierto. Aunque, por supuesto, puede obtener un rescate anticipado con 'reducir' usando' reducido' si lo desea. Y no cambia el hecho de que el rendimiento bruto de reduce es más rápido: para cosas como '(let [v (vec (repeat 1000000 true))] (time (every? Identity v)))' el equivalente de reducción es aproximadamente 3x más rápido en batir toda la secuencia, por ejemplo. – mikera

+0

¿Pero eso solo funciona si sabes la cantidad de argumentos correctos? –

Cuestiones relacionadas