Clojure, un langage de programmation, est maintenant disponible en version 1.2. Ce langage a hérité des traits fonctionnels d'
Haskell, d'
Erlang ou tout simplement de
Lisp, une famille contenant des langages de programmation dits
fonctionnels.
À l'occasion de la sortie de cette nouvelle version, nous en profitons pour vous présenter ce langage que certains d'entre vous ne connaissent peut-être pas, plutôt que de s'attarder sur les nouveautés, qui pourraient vous paraître obscures.
Un langage fonctionnel
Contrairement à la programmation
impérative, le paradigme fonctionnel supprime les changements d'états de ses programmes. Ainsi, la modification de la valeur d'une variable est par exemple interdite. De plus, les boucles n'existent pas car la variable ne changeant pas d'état, la condition serait toujours évaluée à « vrai » ou « faux ». Néanmoins, les boucles ne sont pas utiles dans les langages fonctionnels, étant donné que la récursion permet d'en reproduire le principe.
Certains langages fonctionnels permettent néanmoins les changements d'états : c'est le cas par exemple d'
OCaml. Il est en effet possible de faire une boucle :
for i=1 to 10 do[…]
, caml fait donc partie des langages fonctionnels impurs, il en existe évidemment d'autres. En revanche, des langages comme Haskell, n'autorise pas cet
effet de bord : ce sont des langages fonctionnels purs.
Fonctions
Une fonction reçoit des paramètres et retourne une valeur, ses entrées pouvant être des nombres, des caractères, des chaînes de caractères et des
fonctions. Ce dernier point caractérise le paradigme fonctionnel : des fonctions peuvent en effet prendre en argument des autres fonctions. Des langages comme le C le permettent aussi, mais cela est plus complexe à traiter puisqu'il faut alors passer par des pointeurs de fonctions. Une fonction qui manipule d'autres fonctions est appelée
fonction d'ordre supérieur.
Pour mieux expliquer l'intérêt de ces fonctions, définissons une fonction
sort2
qui prend en arguments une fonction ainsi que deux objets. Cette fonction retourne une liste contenant les deux objets triés selon la fonction passée en argument :
Code : Clojure 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | > (defn sort2 [fun a b]
(if (fun a b)
(list a b)
(list b a)))
> (sort2 > 5 4) ; l'élément le plus grand sera placé en premier
(5 4)
> (sort2 < 5 4) ; ici c'est l'élément le plus petit qui sera en premier
(4 5)
;; ici c'est la chaîne la plus courte qui sera placée en premier (.length
;; calcule la longueur d'une chaîne de caractère)
> (sort2 (fn [a b] (< (.length a) (.length b))) "zéro" "un")
("un" "zéro")
|
Clojure, un puissant dialecte de Lisp
Clojure, créé en 2007 par Rich Hickey, est un dialecte de Lisp. Inspiré par les langages Haskell, Erlang et ML, ce langage de programmation fonctionnel se veut à la fois moderne, efficace et robuste pour la programmation multitâche, simplifiée par la
programmation concurrente.
Clojure possède un typage dynamique des données et un puissant système de
macros qui permet d'étendre les fonctionnalités du langage avec des codes utilisateur.
Voici comment on pourrait définir la macro « when », qui est une forme raccourcie de « if » :
Code : Clojure | (defmacro when
[test & body]
(list 'if test (cons 'do body)))
|
Le code ci-dessus représente la définition de la macro
when
telle qu'elle l'est dans le langage. Elle prend en argument une condition
test et un corps à exécuter
body. Une macro retourne une liste, qui est en fait le code qui sera généré par la macro.
D'autre part, Clojure utilise des
structures de données persistantes et des objets
non-mutables (types de données ne pouvant être modifiées après leur création). De plus, son
évaluation paresseuse lui offre une certaine optimisation étant donné que les séquences ne sont évaluées seulement si elles sont nécessaires par la suite.
Clojure dispose aussi d'une interface interactive (comme le langage Python) qui permet de saisir les commandes à la suite des autres, dans une console. Ce procédé se nomme
REPL et se lance en tapant simplement
clj dans la console. À noter qu'un site nommé
tryclojure permet d'exécuter du code Clojure en ligne, sans installer de logiciel sur votre ordinateur.
Syntaxe
Clojure utilise l'
Expression Symbolique (ou S-expression), une convention concernant la représentation des différentes données des langanges de la famille Lisp. Celle-ci inclut la
notation préfixée (ou polonaise), qui est utilisée dans Clojure. Par exemple, le calcul
((7 + 3) * 2) / 4 s'écrit :
(/ (* 2 (+ 7 3)) 4)
.
Contrairement à la notation habituelle, les opérateurs arithmétiques de Clojure (et des langages Lisp en général) ont une
arité quelconque, cela veut dire qu'ils peuvent recevoir autant de nombres que vous le voulez :
(+ 1 2 3 4 5)
, équivaut à
1 + 2 + 3 + 4 + 5.
Il serait inutile de décrire la syntaxe de tous les types de données de Clojure, voyez plutôt la
documentation.
Néanmoins, voici
quelques différences syntaxiques et sémantiques entre Clojure et les autres langages de la famille des Lisp.
Clojure et Java
Clojure est un langage qui compile du
bytecode utilisable par la
JVM, ce qui fait de lui un langage multiplate-forme. Outre le fait qu'il utilise la machine virtuelle de Java, Clojure est très « proche » de ce dernier. En effet, il offre un accès rapide aux frameworks Java comme
Swing, une bibliothèque graphique, et il est très simple d'appeler un code Clojure au sein d'une application Java. Par exemple, voici une ligne de Clojure qui permet d'afficher « Bonjour les zéros ! » dans une
GUI :
Code : Clojure | (javax.swing.JOptionPane/showMessageDialog nil "Bonjour les zéros !")
|
Pour un exemple plus complet d'utilisation de Swing avec Clojure, consultez
cette page.
La programmation concurrente
Comme dit précédemment, Clojure a été inspiré par Erlang, un langage se basant sur la
programmation concurrente. Ce type de programmation constitue un autre paradigme, différent de l'impératif ou du fonctionnel, qui permet d'exécuter différents morceaux du programme en parallèle, grâce à plusieurs fils d'exécution (
threads). Pour y parvenir, le processeur passe la main à un
thread, exécute un certain nombre d'instructions puis alterne avec un autre
thread, et ainsi de suite. De nos jours, grâce aux processeurs dits « multi-cœurs » ou à la technologie
Hyper-Threading d'Intel, l'exécution de ces différents
threads peut se dérouler en même temps.
Observez donc ce code :
Code : Clojure | (def counter (ref 0)) ; définition d'une variable mutable counter avec la valeur 0
(defn next-counter []
(dosync
(ref-set counter (+ 1 @counter))))
|
counter
est une variable mutable : pour accéder à sa valeur on utilise le symbole
@. Dans l'exemple ci-dessus, on incrémente la variable de 1.
ref-set counter
sert à affecter les modifications à la variable (en C par exemple :
foo += 1; ).
Maintenant, imaginons qu'un processus A fasse appel à
next-counter en même temps qu'un processus B. Le processus B est plus rapide que le A et appelle
next-counter :
counter va donc valoir
1. A lit
@counter
avant que B ne le modifie, A va faire son
ref-set
, ce qui va donc donner
(+ 1 0)
. Or, il y a un problème car
counter
ne vaut plus 0, mais 1. La concurrence règle donc ce type de problèmes, ici grâce à
dosync
qui va s'assurer qu'aucun
thread ne touche à @counter pendant un temps.
Les nouveautés de Clojure 1.2
En plus de la soixantaine de
bugs corrigés, comme à chaque nouvelle version, il y a eu des modifications sur l'implémentation du langage. On peut noter l'amélioration des performances de plusieurs fonctions, la refonte de certains modules (dont le module gérant les fractions), de nouvelles fonctionnalités (possibilité de lancer la documentation Java à partir de l'ERPL, de nouveaux namespaces, support des macros de primitifs de Java, sans boxing), etc.
Comme nous vous l'avons dit en introduction, nous n'avons pas l'intention de nous éterniser sur les nouveautés de cette nouvelle version de Clojure, qui ne vous intéresseraient sans doute pas si vous n'avez jamais entendu parler de Clojure.
Néanmoins, pour ceux qui Clojure intéresse, un lien regroupant toutes les modifications de la version 1.2 est disponible ci-dessous.
Liens et sources
71 Participations
Connectez-vous !
Connectez-vous !
Revenir à la liste des news