Threading macros

En Clojure, on se retrouve facilement à imbriquer les expressions. A force, Cela peut nuire à la lisibilité. Prenons l'exemple suivant:

(reduce + (map inc (filter even? (range 10))))

On voit 4 expressions imbriquées dans ce code. Voyons comment rendre cela plus lisible.

Thread-last: ->>

Le code précédent est équivalent au code suivant:

(->> (range 5)
     (filter even?)
     (map inc)
     (reduce +))

Le symbole ->>, aussi appelé thread-last, est une macro qui agira sur ses paramètres comme suit:

  • le résultat de (range 5) est calculé, ce qui donne (0 1 2 3 4).
  • Ce résultat est placé à la fin de l'expression suivante, qui vaudra maintenant donc (filter even? '(0 1 2 3 4)). Le résultat de cette expression est calculé, et vaut (0 2 4).
  • De la même manière, le résultat précédent est placé à la fin de l'expression suivante, qui vaudra (map inc '(0 2 4)) et donnera comme résultat (1 3 5)
  • Encore une fois, le résultat est passé à l'expression suivante qui vaudra (reduce + '(1 3 5)). Le résultat final sera 9.

Thread-first: ->

La macro précédente permettait de placer les résultats intermédiaires des opérations à la fin de l'expression suivante. La macro ->, aussi appelée thread-first, fonctionne de la même façon sauf qu'ici le résultat est passé comme premier paramètre de l'expression.

Le code suivant:

(/ (:foo {:foo 1}) 100)

qui a comme résultat 0.01 (ou 1/100 si vous êtes sur la JVM) peut être écrit de la manière suivante avec la macro ->:

(-> {:foo 1}
    :foo
    (/ 100))

Ce code peut être déroulé comme suit:

  • {:foo 1} est passé comme paramètre au keyword :foo, ce qui donne 1
  • Ce résultat intermédiaire est passé à (/ 100), ce qui donne (/ 1 100) qui est le résultat final

Conclusion

Les deux macros présentées ici sont celles que l'on rencontre le plus souvent. Il en existe d'autres, qui sont présentées dans cet excellent guide.

Ces macros améliorent grandement la lisibilité du code, vous les rencontrerez donc très souvent.

Précédent - Suivant -

;; thread-last example
(println
 (->> (range 5)
      (filter even?)
      (map inc)
      (reduce +)))

;; thread-first example
(println
 (-> {:foo 1}
     :foo
     (/ 100)))

Powered by mcorbin - Available on Github