2011-11-18 9 views
5

En muchos idiomas, si se escribe algo en la línea de¿Clojure tiene lógica de cortocircuito?

if (foo() || bar() || foobar()) { /* do stuff */ } 

y foo() devuelve verdadero, entonces la barra() y foobar() no será evaluado.

Supongamos que tenía el siguiente código de Clojure:

(let [a (simple-function args) 
     b (complex-function args) 
     c (too-lazy-to-optimize-this-function args)] 
    (or a b c)) 

Si un resultado true, quieren b y también c ser evaluado, o serán ignorados?

Gracias!

Respuesta

12

Desde su respuesta a su propia pregunta, tenga en cuenta que aunque en su ejemplo B y C no pueden evaluarse en la llamada (o abc), el enlace de let se evalúa antes de eso, por lo que la llamada demasiado-perezoso-para-optimizar-esta-función se evalúa de todos modos. Clojure no es tan flojo como eso.

Para que quede claro: para evaluar condicionalmente las llamadas de función, es necesario poner la expresión de evaluación de las mismas en la llamada or, básicamente:

(or (simple-function args) 
    (complex-function args) 
    (too-lazy-to-optimize-this-function args)) 
+0

que estoy aceptando esta porque discute Gotcha que yo desconocía. – Joel

+4

No es un gotcha, más bien tienes que entender que todo está ansioso excepto las secuencias perezosas y las funciones que funcionan en ellas. Los 'o' cortocircuitos ya que es una macro, se expande a http://bit.ly/u8xnms. Si fuera una función, evaluaría sus argumentos. En cambio, macroexpands a un if, que es una forma especial y cortocircuitos. – gtrak

1

Tan pronto como terminé de escribir esta pregunta, me di cuenta de que podía mirar la documentación para 'o'.

A partir de los documentos: "Evalúa exprs uno a la vez, de izquierda a derecha Si un formulario devuelve un valor verdadero lógico, o devuelve ese valor y no hace evaluar cualquiera de las otras expresiones, de lo contrario. devuelve el valor de la última expresión. (o) devuelve nil ".

4

En caso de duda, consulte a the documentation:

o
macro
Uso:

(or) 
    (or x) 
    (or x & next) 

Evalúa exprs uno a la vez, de izquierda a derecha. Si un formulario devuelve un valor verdadero lógico, o devuelve ese valor y no evalúa cualquiera de las otras expresiones, de lo contrario, devuelve el valor de la última expresión. (o) devuelve nil.

(Énfasis mío.)

El documentation for and muestra se comporta de la manera equivalente también.

0
if (foo() || bar() || foobar()) { /* do stuff */ } 

a

(if (or (foo) (bar) (boobar)) (comment do stuff)) 

o

(when (or (foo) (bar) (boobar)) (comment do stuff)) 
10

Las otras respuestas todo bien, pero en caso de duda, se puede siempre solo pruébelo en el REPL:

user=> (or true (do (println "hello") true)) 
true 
user=> (or false (do (println "hello") true)) 
hello 
true 
+0

+1 para demostrar en lugar de declarar! – mikera

1

Sí, Clojure sí tiene una evaluación de cortocircuito.

Una característica interesante en Clojure/otros Lisps es que también es posible ampliar el lenguaje con nuevas construcciones que también proporcionan una evaluación de cortocircuito. Esto no se puede hacer utilizando funciones en la mayoría de los otros lenguajes, ya que todos los parámetros de una función deben evaluarse antes de llamar a la función.

He aquí un ejemplo de una macro para implementar una función NAND cortocircuitos en Clojure:

(defmacro nand 
    ([x] 
    `(not ~x))    ; NAND is equivalent to NOT for one argument 
    ([x & xs] 
    `(let [nand# (not ~x)] 
     (if nand# 
     true    ; short circuit if we can prove the nand is true 
     (nand [email protected]))))) ; continue with the other expressions otherwise 

(nand true true) 
=> false 

(nand false (println "Expression with a side effect!")) 
=> true 
Cuestiones relacionadas