web-dev-qa-db-fra.com

si-ramification en clojure

J'apprends moi-même Clojure.

Dans un langage non-FP, je pourrais facilement écrire des ifs imbriqués, et si je ne mettais pas spécifiquement une autre chose, le contrôle découlerait simplement du bloc if. Par exemple:

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

Cependant, dans Clojure, il n'y a pas d'instruction return (à ma connaissance), donc si j'écris:

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

alors il n'y a pas de "retour" sur "quelque chose". Il semble juste dire, ok, ici nous avons une valeur, maintenant continuons à exécuter. La solution évidente serait de combiner les conditions, à savoir:

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

mais cela devient difficile à manier/laid pour de grandes conditions. En outre, il faudrait plus de précision pour ajouter une déclaration à la partie "else" de cond1. Existe-t-il une solution élégante à cela?

25
Kricket

C'est la différence subtile entre approche impérative et approche fonctionnelle. Avec impératif, vous pouvez placer return à n’importe quel endroit de la fonction, tandis que pour fonctionnel, le meilleur moyen consiste à avoir des chemins d’exécution clairs et explicites. Certaines personnes (moi y compris) préfèrent également cette dernière approche dans la programmation impérative, la reconnaissant comme plus évidente et plus facile à gérer et moins sujette aux erreurs.

Pour rendre cette fonction explicite:

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

  return somethingelse;
}

Vous pouvez le refactoriser pour:

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

En Clojure, son équivalent est:

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

Si vous avez besoin d'un "else", votre version de Java pourrait devenir:

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

... et son équivalent Clojure:

(defn myfunc []
  (if cond1
      (if cond2 something newelse)
      somethingelse))
31
Konrad Garus
(if (and (cond1) (cond2))
     something
     somethingelse)

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

cond le fait si vous voulez comparer la même chose; dans un cas de figure, vous pouvez utiliser condp.

Je ne vois pas ce genre de code très souvent, mais c'est la façon de le faire.

15
nickik

Les langages impératifs ont des instructions if qui disent if this then do that else do that et les langages fonctionnels ont des expressions if qui disent if this return that else return this. C'est une manière différente de voir la même idée, qui reflète une approche très différente de l'expression des problèmes. en langages fonctionnels tout a une valeur, vraiment tout, même si vous ne faites rien avec cette valeur.

Quand je faisais la transition, cela m'a beaucoup aidé de me demander "quel résultat cette fonction devrait-elle renvoyer" au lieu de la question "que doit cette fonction faire" à laquelle j'avais l'habitude de demander. 

14
Arthur Ulfeldt

Il n'y a pas d'instruction de retour explicite dans Clojure, mais votre code "retournera" sur "quelque chose" parce que vous n'avez aucune expression après cette if et dans Clojure, le résultat de la dernière expression est utilisé comme valeur de retour de la fonction .

7
Nevena

Vous pouvez également utiliser 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")))
0
amir-t