Objective Caml
Un article de Wikipédia, l'encyclopédie libre.
Cet article (ou cette section) est à recycler. Sa qualité peut être largement améliorée en le réorganisant et en le clarifiant.
L'utilisateur qui appose ce bandeau est invité à énoncer les points à améliorer en page de discussion.
Cet article fait partie de la série Langages de programmation |
Langages à objets |
C++ - C# Delphi - Eiffel - Java Groovy - Python - Ruby Simula - Smalltalk Visual Basic - WinDev |
Langages impératifs |
APL - ASP - Assembleur BASIC - C - Cobol Forth - Fortran - Logo Pascal - Limbo - Perl - PHP |
Langages fonctionnels |
Haskell - ML/OCaml Lisp/Common Lisp Scheme XSLT |
Langages déclaratifs |
Clips - Prolog |
Langages concurrents |
Ada 95 - Erlang |
Langage de balisage |
HTML - SGML - XML S-expressions |
Voir aussi |
Conception - Codage Tests - Optimisations |
Le langage Objective Caml, aussi appelé OCaml ou encore O'Caml, est un langage de programmation avancé de la famille des langages ML, développé et distribué par l'INRIA, projet Gallium(ex Cristal). Son principal concepteur et développeur est Xavier Leroy.
Sommaire |
[modifier] Fonctionnalités et utilisations
Il permet aussi bien la programmation impérative que la programmation fonctionnelle. Ocaml est la principale implémentation du langage Caml (acronyme qui signifiait à l'origine Categorical Abstract Machine Language). Il représente une évolution de l'implémentation légère Caml Light auquel il ajoute les concepts de la programmation orientée objet et de la programmation modulaire, ainsi que des améliorations syntaxiques.
Le code source peut aussi bien être compilé en code intermédiaire (ou bytecode) à l'instar de Java ou en code natif pour de nombreuses architectures, dont IA32, IA64, PowerPC, AMD64, Sparc, Alpha, HP/PA, MIPS et StrongARM. Le compilateur natif est réputé pour sa grande efficacité, comparable à celle des compilateurs C++.
Objective Caml dispose d'un typage statique et automatique avec inférence de types, de fonctions de première classe, du polymorphisme paramétrique, du pattern matching, de la fermeture lexicale, d'une gestion d'exceptions, et d'une gestion de mémoire automatisée. L'implémentation du ramasse-miettes (garbage collector en anglais) de type incrémental générationnel est particulièrement performante. À cela s'ajoute un système de modules récursifs et paramétrables ainsi qu'un système de classes évolué. Toutes ces caractéristiques, associées à un préprocesseur perfectionné, rendent le langage particulièrement expressif et sûr.
Bien que très utilisé pour l'enseignement de la programmation et la recherche, l'orientation généraliste d'Objective Caml ainsi qu'une base de bibliothèques importante lui trouvent des applications dans de nombreux domaines : bio-informatique, base de données généalogiques (GeneWeb), jeux, compilateurs, système de preuve formelle (Coq), serveurs internet, création de prototypes, etc.
[modifier] Notions de base en Caml
Pour comprendre la suite, il faut savoir ce qu'est un langage fonctionnel fortement typé. Résumons en disant que Caml (et ici OCaml) ne fait "que" créer des fonctions où les valeurs d'entrée et de sortie sont parfaitement déterminés à la compilation, avant toute exécution.
[modifier] Les types prédéfinis de Caml
Citons entre autres, les bool, int, float, string de base, lorsque c'est utile, un type générique 'a, les listes 'a list, les tableaux 'a array, les couples (de manière générale: ('a * 'b)), les références 'a ref les options 'a option .... et les types que l'on peut définir soi-même (par exemple, les arbres ci-dessous).
[modifier] Définitions de variables et fonctions
[modifier] Variables
Simplement, à l'instar des maths, on écrit
# let x = 3;;
pour définir une variable x contenant la valeur 3.
val x : int = 3
Remarquez la différence...
#let y = 3.;; val y : float = 3.
Caml distingue clairement les entiers et les flottants! Ce qui provoque une grande source d'erreurs pour les débutants!
#x+1;; -: int = 4 #y+.1.;; -: float = 4. #y + 1.;; Characters 1 - 3: y + 1.;; ^^ This expression has type float but is here used with type int #y +. 1;; Characters 6 - 7: y +. 1;; ^^ This expression has type int but is here used with type float #y +. x;; Characters 6 - 7: y +. x;; ^^ This expression has type int but is here used with type float
Des erreurs typiques que tout le monde a déjà fait...
[modifier] Fonctions
On peut écrire
# let f x = x;;
ou
# let f = function x -> x;;
ou encore
# let f = fun x -> x;;
dans tous les cas on a:
val f: 'a -> 'a = <fun>
Notez que Caml est "assez grand " pour reconnaître les types des fonctions! Et lorsque ce n'est pas concordant, il se "plaint":
#let mauvaise_fonction x y = x + (y +. 1.);; Characters ... - ...: x + (y +. 1.);; ^^^^^^^^^ This expression has type float but is here used with type int
[modifier] Exemples de code
[modifier] Hello world
Pour afficher un message, on dispose d'une fonction:
#print_string;; - : string -> unit = <fun>
ceci signifie: "print_string est une fonction prenant un string en paramètre et ne retourne un résultat de type unit". Lorsqu'une fonction Caml a pour valeur de retour unit, cela veut dire qu'elle ne renvoie pas de valeur; c'est un peu le résultat attendu pour une fonction d'affichage...
L'affichage d'un message s'écrit
print_string "Hello world";;
L'exécution de cette ligne de commandes dans votre interface OCaml favorite vous donne:
Hello world - : unit = ()
soit:
- d'une part, l'affichage de "Hello world" à l'écran,
- d'autre part, la valeur de retour de la fonction, mais comme on a déjà dit, cette expression n'a aucun résultat, on a ().
À l'aide de l'environnement OCaml, on peut vérifier
# "Hello world";; - : string = "Hello world"
c'est-à-dire que "Hello world" est une chaîne de caractères.
Si l'on essaie d'exécuter
# 3.85;; -: float: 3.85 # print_string 3.85;;
on obtient en retour:
Characters 13 - 16: print_string 3.85 ^^^^ This expression has type float but is here used with type string.
En effet, le typage fort de OCaml ne permet pas d'imprimer à l'écran des nombres à l'aide de print_string. Deux solutions sont offertes:
- soit utiliser print_float
- soit convertir 3.85 en string via la fonction string_of_float.
[modifier] Manipulation de listes
Ceci déclare une liste de chaînes de caractères
# let l = ["La"; "vie"; "est"; "un"; "long"; "fleuve"; "tranquille"];; val l : string list = ["La"; "vie"; "est"; "un"; "long"; "fleuve"; "tranquille"]
Par opposition, il n'est pas possible de définir une liste qui mélange des éléments de plusieurs types.
# let l = ["La"; "vie"; "est"; 1 ; "long"; "fleuve"; "tranquille"];; This expression has type int but is here used with type string
(* Les exemples ci-dessous fonctionnent sur des listes de n'importe quel type *) (* Longueur d'une liste *) let rec longueur = function | [] -> 0 | x :: xs -> 1 + longueur xs;;
Le type de cette expression (déterminé automatiquement par le compilateur) est
val longueur : 'a list -> int = <fun>
ce qui se lit cette expression définit la valeur longueur . Cette valeur est une fonction qui, pour tout type 'a prend comme argument une liste d'éléments de type 'a et renvoie un entier.
(* Tri d'une liste par insertion *) (* Une relation d'ordre doit être définie *) let rec trie = function | [] -> [] | x :: xs -> insere x (trie xs) and insere e = function |[] -> [e] | x :: xs -> if x > e then e :: x :: xs else x :: (insere e xs);;
Le type de ces fonctions est
val trie : 'a list -> 'a list = <fun> val insere : 'a -> 'a list -> 'a list = <fun>
Soit, pour tout type 'a trie prend une liste d'éléments de type 'a et renvoie une liste d'éléments de type 'a.
(* Tri rapide (quicksort ou tri de Hoare) d'une liste *) let rec qsort = function | [] -> [] | x :: l -> let rec coupelist = function | [] -> [], [] | y :: m -> let a, b = coupelist m in if y < x then y :: a, b else a, y :: b in let debut, fin = coupelist l in (qsort debut) @ [x] @ (qsort fin);;
# longueur l;; - : int = 7
# trie l;; - : string list = ["La"; "est"; "fleuve"; "long"; "tranquille"; "un"; "vie"]
[modifier] Arbres
(* Définition d'un arbre binaire, d'un type quelconque 'a *) type 'a arbre = Empty | Arbre of ('a arbre * 'a * 'a arbre);;
let a = Arbre(Empty, 4, Arbre(Empty, 2, Empty));; (*a est schématiquement l'arbre suivant: 4 / \ x 2 / \ x x où les 'x' désignent des sous-arbres vides.*)
(* Hauteur de l'arbre *) let rec hauteur = function |Empty -> 0 |Arbre(gauche, _, droit) -> 1 + max (hauteur gauche) (hauteur droit) ;; # hauteur a;; - : int = 2
[modifier] Recherche de racine par dichotomie
let rec dicho f min max eps = let fmin = f min and fmax = f max in if fmin *. fmax > 0. then failwith "Aucune racine" else if max -. min < eps then (min, max) (* retourne un intervalle *) else let mil = (min +. max) /. 2. in if (f mil) *. fmin < 0. then dicho f min mil eps else dicho f mil max eps ;;
(* Approximation de la racine carrée de 2 *) # dicho (fun x -> x *. x -. 2.) 0. 10. 0.000000001;; - : float * float = (1.4142135618, 1.41421356238)
[modifier] Liens externes
- site OCaml officiel de l'Inria
- www.ocaml.org le même site, avec un nom plus facile à retenir.
- Le CocanWiki (en) Un wiki dédié au langage Ocaml et ses applications industrielles.
- Développement d'applications avec Objective Caml, livre O'Reilly en ligne (publié en 2002 mais reste très complet).
- cours de programmation en Caml pour débutants
- A brief history of Caml (as I remember it) (en)