Section courante

A propos

Section administrative du site

Les premiers pas

Vous trouverez ci-dessous des exemples de représentations littérales de types primitifs courants en Clojure. Toutes ces représentations sont des expressions Clojure valides.

Le point-virgule (;) insère un commentaire en fin de ligne. L'utilisation de plusieurs points-virgules pour délimiter des sections de commentaires d'entête est parfois une convention.

Types numériques

  1. 42        ; entier
  2. -1.5      ; virgule flottante
  3. 22/7      ; ratio

Les entiers sont lus en précision fixe 64 bits lorsqu'ils sont compris dans la plage autorisée, et en précision arbitraire dans le cas contraire. Un N à la fin permet de forcer une précision arbitraire. Clojure prend également en charge la syntaxe Java pour les entiers octaux (préfixe 0), hexadécimaux (préfixe 0x) et à base arbitraire (préfixe base, puis r, par exemple 2r pour le binaire). Les ratios sont fournis comme un type spécifique combinant un numérateur et un dénominateur.

Les nombres à virgule flottante sont lus en double précision 64 bits, ou en précision arbitraire avec un suffixe M. La notation exponentielle est également prise en charge. Les valeurs symboliques spéciales ##Inf, ##-Inf et ##NaN représentent respectivement l'infini positif, l'infini négatif et la valeur «non numérique».

Types de caractères

  1. "bonjour"       ; chaîne de caractères
  2. \              ; caractère
  3. #"[0-9]+"       ; expression régulière

Les chaînes de caractères sont placées entre guillemets doubles et peuvent s'étendre sur plusieurs lignes. Chaque caractère est précédé d'une barre oblique inverse. Il existe quelques caractères spéciaux : \newline, \space, \tab, etc. Les caractères Unicode peuvent être représentés par \uNNNN ou, en octal, par \oNNN.

Les expressions régulières littérales sont des chaînes de caractères commençant par un #. Elles sont compilées en objets java.util.regex.Pattern.

Symboles et identifiants

  1. map             ; symbole
  2. +               ; symbole - la plupart des signes de ponctuation sont autorisés
  3. clojure.core/+  ; symbole d'espace de noms
  4. nil             ; valeur nulle
  5. true false      ; booléennes
  6. :alpha          ; mot-clef
  7. :release/alpha  ; mot-clef avec espace de noms

Les symboles sont composés de lettres, de chiffres et d'autres signes de ponctuation. Ils servent à désigner un élément, comme une fonction, une valeur, un espace de noms, etc. Un symbole peut avoir un espace de noms, séparé de son nom par une barre oblique.

Trois symboles spéciaux sont interprétés comme des types différents : `nil` représente la valeur nulle, et `true` et `false` représentent les valeurs booléennes.

Les mots-clefs commencent par un deux-points et s'évaluent toujours à eux-mêmes. Ils sont fréquemment utilisés comme valeurs énumérées ou noms d'attributs en Clojure.

Collections littérales

Clojure inclut également une syntaxe littérale pour quatre types de collections :

  1. '(1 2 3)     ; liste
  2. [1 2 3]      ; vecteur
  3. #{1 2 3}     ; ensemble
  4. {:a 1, :b 2} ; carte

Nous aborderons ces points plus en détail ultérieurement ; pour l'instant, il suffit de savoir que ces quatre structures de données peuvent être utilisées pour créer des données composites.

Évaluation

Nous allons maintenant examiner comment Clojure lit et évalue les expressions.

Évaluation traditionnelle (Java)

En Java, le code source (fichiers .java) est lu comme des caractères par le compilateur (javac), produisant du bytecode (fichiers .class) pouvant être chargé par la JVM.

Évaluation avec Clojure

En Clojure, le code source est lu comme des caractères par le lecteur. Ce dernier peut lire le code source à partir de fichiers .clj ou recevoir une série d'expressions de manière interactive. Le lecteur produit des données Clojure. Le compilateur Clojure génère ensuite le bytecode pour la JVM.

Deux points importants sont à retenir :

Structure vs Sémantique

Prenons l'exemple d'une expression Clojure :

Ce diagramme illustre la différence entre la syntaxe (en vert, la structure de données Clojure produite par le lecteur) et la sémantique (en bleu, la manière dont ces données sont interprétées par l'environnement d'exécution Clojure).

La plupart des formes littérales Clojure s'évaluent directement, à l'exception des symboles et des listes. Les symboles servent à référencer un élément et, lorsqu'ils sont évalués, renvoient cet élément. Les listes (comme dans le diagramme) sont évaluées comme des invocations.

Dans le diagramme, `+ 3 4` est interprété comme une liste contenant le symbole `+` et deux nombres (3 et 4). Le premier élément (où se trouve `+`) peut être considéré comme la «position de la fonction», c'est-à-dire l'emplacement où trouver l'élément à appeler. Bien que les fonctions soient des éléments évidents à appeler, il existe également quelques opérateurs spéciaux reconnus par l'environnement d'exécution, des macros et d'autres éléments invocables.

Considérons l'évaluation de l'expression ci-dessus :

De nombreux langages utilisent à la fois des instructions et des expressions. Les instructions ont un effet d'état, mais ne renvoient pas de valeur. En Clojure, tout est une expression qui s'évalue en une valeur. Certaines expressions (mais pas la plupart) ont également des effets de bord.

Voyons maintenant comment évaluer interactivement des expressions en Clojure.

Retarder l'évaluation grâce aux guillemets

Il est parfois utile de suspendre l'évaluation, notamment pour les symboles et les listes. Parfois, un symbole doit simplement être considéré comme tel, sans qu'on cherche à comprendre ce à quoi il fait référence :

  1. user=> 'x
  2. x

Et parfois, une liste ne devrait être qu'une liste de valeurs de données (et non du code à évaluer) :

  1. user=> '(1 2 3)
  2. (1 2 3)

Une erreur déroutante que vous pourriez rencontrer résulte d'une tentative accidentelle d'évaluer une liste de données comme s'il s'agissait de code :

  1. user=> (1 2 3)
  2. Execution error (ClassCastException) at user/eval156 (REPL:1).
  3. class java.lang.Long cannot be cast to class clojure.lang.IFn

Pour l'instant, ne vous préoccupez pas trop des citations, mais vous les verrez occasionnellement dans ces documents afin d'éviter l'évaluation de symboles ou de listes.

REPL

La plupart du temps, lorsque vous utilisez Clojure, vous le faites dans un éditeur ou une console REPL (Read-Eval-Print-Loop). La console REPL comprend les étapes suivantes :

  1. Lire une expression (une chaîne de caractères) pour produire des données Clojure.
  2. Évaluer les données renvoyées par l'étape 1 pour obtenir un résultat (également des données Clojure).
  3. Afficher le résultat en le reconvertissant en caractères.
  4. Retour au début.

Un aspect important du point n° 2 est que Clojure compile toujours l'expression avant de l'exécuter ; Clojure est toujours compilé en bytecode JVM. Il n'existe pas d'interpréteur Clojure.

  1. user=> (+ 3 4)
  2. 7

L'encadré ci-dessus illustre l'évaluation d'une expression (+ 3 4) et l'obtention d'un résultat.

Exploration du REPL

La plupart des environnements REPL proposent quelques astuces pour faciliter l'utilisation interactive. Par exemple, certains symboles spéciaux conservent en mémoire les résultats des trois dernières évaluations :

  1. user=> (+ 3 4)
  2. 7
  3. user=> (+ 10 *1)
  4. 17
  5. user=> (+ *1 *2)
  6. 24

De plus, l'espace de noms clojure.repl, inclus dans la bibliothèque Clojure standard, fournit plusieurs fonctions utiles. Pour charger cette bibliothèque et rendre ses fonctions disponibles dans notre contexte actuel, appelez :

  1. (require '[clojure.repl :refer :all])

Pour l'instant, considérez cela comme une formule magique. Et voilà ! Nous l'expliquerons plus en détail lorsque nous aborderons les espaces de noms.

Nous avons maintenant accès à des fonctions supplémentaires utiles dans le REPL : `doc`, `find-doc`, `apropos`, `source` et `dir`.

La fonction `doc` affiche la documentation de n'importe quelle fonction. Appelons-la avec le symbole `+`:

  1. user=> (doc +)
  2.  
  3. clojure.core/+
  4. ([] [x] [x y] [x y & more])
  5.   Returns the sum of nums. (+) returns 0. Does not auto-promote
  6.   longs, will throw on overflow. See also: +'

La fonction `doc` affiche la documentation de l'opérateur `+`, y compris les signatures valides.

La fonction `doc` affiche la documentation, puis renvoie `nil` comme résultat ; vous verrez les deux dans le résultat de l'évaluation.

On peut également appeler `doc` sur elle-même :

  1. user=> (doc doc)
  2.  
  3. clojure.repl/doc
  4. ([name])
  5. Macro
  6.   Prints documentation for a var or special form given its name

Vous ne savez pas comment s'appelle une fonction ? Vous pouvez utiliser la commande apropos pour trouver les fonctions correspondant à une chaîne de caractères ou à une expression régulière particulière.

  1. user=> (apropos "+")
  2. (clojure.core/+ clojure.core/+')

Vous pouvez également élargir votre recherche pour inclure les chaînes de documentation elles-mêmes avec find-doc :

  1. user=> (find-doc "trim")
  2.  
  3. clojure.core/subvec
  4. ([v start] [v start end])
  5.   Returns a persistent vector of the items in vector from
  6.   start (inclusive) to end (exclusive).  If end is not supplied,
  7.   defaults to (count vector). This operation is O(1) and very fast, as
  8.   the resulting vector shares structure with the original and no
  9.   trimming is done.
  10.  
  11. clojure.string/trim
  12. ([s])
  13.   Removes whitespace from both ends of string.
  14.  
  15. clojure.string/trim-newline
  16. ([s])
  17.   Removes all trailing newline \ or return \ characters from
  18.   string.  Similar to Perl's chomp.
  19.  
  20. clojure.string/triml
  21. ([s])
  22.   Removes whitespace from the left side of string.
  23.  
  24. clojure.string/trimr
  25. ([s])
  26.   Removes whitespace from the right side of string.

Pour afficher la liste complète des fonctions d'un espace de noms particulier, vous pouvez utiliser la fonction `dir`. Ici, nous l'utilisons sur l'espace de noms `clojure.repl` :

  1. user=> (dir clojure.repl)
  2.  
  3. apropos
  4. demunge
  5. dir
  6. dir-fn
  7. doc
  8. find-doc
  9. pst
  10. root-cause
  11. set-break-handler!
  12. source
  13. source-fn
  14. stack-element-str
  15. thread-stopper

Enfin, nous pouvons voir non seulement la documentation, mais aussi le code source sous-jacent de toute fonction accessible par l'environnement d'exécution :

  1. user=> (source dir)
  2.  
  3. (defmacro dir
  4.   "Prints a sorted directory of public vars in a namespace"
  5.   [nsname]
  6.   `(doseq [v# (dir-fn '~nsname)]
  7.      (println v#)))

Tout au long de cet atelier, n'hésitez pas à consulter la documentation et le code source des fonctions que vous utilisez. Explorer l'implémentation de la bibliothèque Clojure est un excellent moyen d'approfondir vos connaissances sur le langage et son utilisation.

Il est également fortement conseillé de garder sous la main le guide de référence Clojure (Clojure Cheatsheet) pendant votre apprentissage. Ce guide catégorise les fonctions disponibles dans la bibliothèque standard et constitue une ressource précieuse.

Voici maintenant quelques notions de base de Clojure pour bien démarrer...

Notions de base de Clojure

def

Lors de l'évaluation de données dans un REPL, il peut être utile de sauvegarder une donnée pour une utilisation ultérieure. On peut le faire avec la fonction `def` :

  1. user=> (def x 7)
  2. #'user/x

La fonction `def` est une forme spéciale qui associe un symbole (`x`) de l'espace de noms courant à une valeur (`7`). Cette association est appelée une variable (`var`). Dans la plupart des cas, les variables font référence à une constante ou à une fonction, mais il est courant de les définir et de les redéfinir par commodité dans l'interpréteur interactif (REPL).

Notez que la valeur de retour ci-dessus est `#'user/x`, soit la représentation littérale d'une variable : `#'` suivi du symbole dans l'espace de noms. `user` est l'espace de noms par défaut.

Rappelons que les symboles sont évalués en recherchant ce à quoi ils font référence. On peut donc récupérer la valeur en utilisant simplement le symbole :

  1. user=> (+ x x)
  2. 14

Affichage

L'une des opérations les plus courantes lors de l'apprentissage d'un langage consiste à afficher des valeurs. Clojure propose plusieurs fonctions pour cela :

  Pour les humains Lisible sous forme de données
Avec saut de ligne println prn
Sans saut de ligne print pr

Les formes lisibles par l'humain traduisent les caractères d'impression spéciaux (comme les sauts de ligne et les tabulations) en leur forme affichée et omettent les guillemets dans les chaînes de caractères. On utilise souvent `println` pour déboguer des fonctions ou afficher une valeur dans l'interpréteur interactif (REPL). `println` accepte un nombre quelconque d'arguments et insère un espace entre la valeur affichée de chaque argument :

  1. user=> (println "Qu'est-ce que c'est:" (+ 1 2))
  2. Qu'est-ce que c'est: 3

La fonction `println` a des effets de bord (affichage) et renvoie `nil`.

Notez que «Qu'est-ce que c'est:» ci-dessus n'affiche pas les guillemets et ne constitue pas une chaîne de caractères que le lecteur pourrait relire comme données.

Pour cela, utilisez `prn` afin d'afficher les données :

  1. user=> (prn "one\n\ttwo")
  2. "one\n\ttwo"

Le résultat affiché est désormais un format valide que le lecteur peut relire. Selon le contexte, vous pouvez privilégier soit le format texte, soit le format de données.



Dernière mise à jour : Lundi, le 2 février 2026