2011-02-09 13 views
24

estoy enseñando a mí mismo Clojure.if-else ramificación en clojure

En un lenguaje no-FP, que podría fácilmente lo suficiente contra escritura si anidado de, y si no puse específicamente una persona, entonces el control se acaba de fluir fuera del bloque if. Por ejemplo:

Thing myfunc() 
{ 
    if(cond1) 
    { 
    if(cond2) 
     return something; 
    } 
    return somethingelse; 
} 

Sin embargo, en Clojure, no hay ninguna instrucción de retorno (que yo sepa), por lo que si escribo:

(defn myfunc [] 
    (if (cond1) 
     (if (cond2) something)) 
    somethingelse) 

entonces no hay "vuelta" en "algo". Parece que solo digo, vale, aquí tenemos un valor, ahora sigamos ejecutando. La solución obvia sería combinar las condiciones, es decir .:

(if (and (cond1) (cond2)) 
    something 
    somethingelse) 

pero ahora se pone difícil de manejar/fea para condiciones de gran tamaño. Además, tomaría una trampa adicional agregar una declaración a la parte "else" de cond1. ¿Hay algún tipo de solución elegante para esto?

+0

no veo cómo se conseguiría "difícil de manejar". ¿Puedes presentar algún ejemplo? – Svante

+0

El problema en el que estaba trabajando consistía en verificar si dos números tenían 3 dígitos. Me pareció muy feo escribir (if (y (= 3 (count (str num1))) (= 3 (count (str num2)))) something) – Kricket

+1

¡Parece que necesitas una función! '(defn tres? [num] (= 3 (count (str num))))' Entonces todo lo que necesitas es '(if (y (three? num1) (three? num2)) something)' – Jeremy

Respuesta

30

Ésta es la sutil diferencia entre el enfoque imperativo y funcional. Con imperativo, puede colocar return en cualquier lugar de la función, mientras que con funcional la mejor manera es tener vías de ejecución claras y explícitas. Algunas personas (yo incluido) prefieren este último enfoque también en la programación imperativa, reconociéndolo como más obvio y manejable, y menos propenso a errores.

Para hacer esta función explícita:

Thing myfunc() { 
    if(cond1) { 
    if(cond2) 
     return something; 
    } 

    return somethingelse; 
} 

Usted puede refactorizar a:

Thing myfunc() { 
    if(cond1 && cond2) { 
     return something; 
    } else { 
    return somethingelse; 
    } 
} 

En Clojure, su equivalente es:

(defn myfunc [] 
    (if (and cond1 cond2) 
     something 
     somethingelse)) 

Si necesita un "else ", su versión de Java podría llegar a ser:

Thing myfunc() { 
    if(cond1) { 
    if(cond2) { 
     return something; 
    } else { 
     return newelse; 
    } 
    } else { 
    return somethingelse; 
    } 
} 

... y su equivalente Clojure:

(defn myfunc [] 
    (if cond1 
     (if cond2 something newelse) 
     somethingelse)) 
+2

Tiene que usar cuando en el último ejemplo no si – nickik

+0

no, no es así. todos los valores son expresiones únicas. –

+0

"cuando" siempre tiene más sentido que "si" en la programación en mi opinión. pero por supuesto, eso es solo una cuestión de estilo. – sova

15
(if (and (cond1) (cond2)) 
    something 
    somethingelse) 

(cond 
    (and (cond1) (cond2)) something 
    :else somethingelse) 

cond hace hacer esto si se quiere comparar la misma cosa; en una caja de interruptores puede usar condp.

no veo ese tipo de código muy a menudo, pero esa es la manera de hacerlo.

+1

+ 1 para 'condp'. – charleslparker

7

No hay ninguna instrucción de retorno explícito en Clojure, pero su código será "volver" sobre "algo", ya que no tiene ninguna expresión después de que if y en Clojure el resultado de la última expresión se utiliza como la función de valor de retorno.

14

Imperativo Los lenguajes tienen sentencias if que dicen if this then do that else do that y los lenguajes funcionales tienen if-expressions que dicen if this return that else return this. es una forma diferente de ver la misma idea, que refleja un enfoque muy diferente para expresar problemas. en lenguajes funcionales todo tiene un valor, realmente todo, incluso si usted no hace nada con ese valor.

cuando estaba haciendo la transición que ha ayudado mucho a hacer a mi mismo "¿qué resultado debe esta función de retorno" en lugar de la pregunta "¿qué deben hacer esta función" que yo estaba acostumbrado a preguntar.

0

También es posible usar la macro (cond):

(defn length-checker [a b] 
    (cond 
    (= 3 (count (str a))) (if (= 3 (count (str b))) 
        (println "both numbers are 3 digits long") 
        (println "first number is 3 digits, but the 2nd not!")) 
    :else (println "first- or both of the numbers are not 3 digits")))