• Aucun résultat trouvé

[PDF] Introduction aux objets du langage Caml | Cours informatique

N/A
N/A
Protected

Academic year: 2021

Partager "[PDF] Introduction aux objets du langage Caml | Cours informatique"

Copied!
32
0
0

Texte intégral

(1)

Jeudi 7 avril 2005 – David Mentré

OCaml

caml.inria.fr

« Pourquoi c'est (presque ;-) le meilleur

langage du monde »

(2)

OCaml en quelques mots

OCaml est un langage de programmation :

– fortement typé, à typage polymorphe – à inférence de type

– types de données algébriques et filtrage – fonctionnel supérieur, impératif et objet – avec exceptions

– avec un ramasse miettes – efficace

– compilateur libre (QPL compatible DFSG & LGPL)

(3)

Petit historique

1985 : langages de la famille ML (dont Caml)

– développé à l'INRIA

– comme support pour des assistants de preuve

● par ex. : Coq de l'INRIA

1990 : système Caml Light

– byte code efficace

1996 : OCaml (Objective Caml)

– objet

– compilateur natif – ... et tout le reste

(4)

Démarrage : les types

Utiliser l'interpréteur pour découvrir OCaml

Toutes les expressions sont typées

$ ocaml

Objective Caml version 3.08.2 # 1;; - : int = 1 # "toto";; - : string = "toto" # [|1; 2|];; - : int array = [|1; 2|] # [true; false];;

(5)

Types de base, fonctions

Types classiques

– booléens, entiers, flottants, chaînes, tuples,

tableaux, listes, ...

– structures de données plus complexes

● ensembles, table de hachage, ...

Variables

Fonctions

# let carre x = x * x;;

val carre : int -> int = <fun>

# let pi = 4.0 *. atan 1.0;;

(6)

Avantages du typage d'OCaml

Avantage du typage fort ?

– détection des erreurs dès la compilation

Oui mais rentrer les types c'est lourd !

– c'est pourquoi on a une inférence de type

● le compilateur trouve les types, comme un grand

# let carre_flottant x = x *. x;;

val carre_flottant : float -> float = <fun> # let carre x = x * x;;

val carre : int -> int = <fun> # carre 4.0;;

(7)

Type Somme et filtrage

Définir les différentes alternatives

Traiter chaque cas dans une fonction

# type chocolat = Noir | Lait;;

type chocolat = Noir | Lait

# let j_aime = Noir;;

val j_aime : chocolat = Noir # let bon_chocolat choco = match choco with | Noir -> true

| Lait -> false;;

val bon_chocolat : chocolat -> bool = <fun> # bon_chocolat Noir;;

(8)

Avantage du filtrage

On n'oublie pas un cas !

– si on l'utilise de manière systématique, ces bugs

sont évités

● le compilateur le dit

– structures de données correctes par

construction

# let bon_chocolat choco = match choco with

| Noir -> true;;

Warning: this pattern-matching is not exhaustive. Here is an example of a value that is not matched:

Lait

(9)

Polymorphisme

Une fonction est générique

– elle marche sur plusieurs types ('a ≡ )

# List.rev;;

- : 'a list -> 'a list = <fun> # List.rev [1; 2; 3; 4];;

- : int list = [4; 3; 2; 1]

# List.rev ["langage"; "super"; "un"];;

- : string list = ["un"; "super"; "langage"] # List.rev [Noir; Lait];;

- : chocolat list = [Lait; Noir]

# List.map;;

(10)

Avantage du polymorphisme

Les programmes sont génériques

– fonctionnalités similaires dans d'autres langages

● ex. : Ada, Eiffel, template C++

– en OCaml, le polymorphisme arrive tout seul

avec l'inférence de type

Combinable avec d'autres constructions

– comme les types Somme

(11)

Filtrage et type somme polymorphe

# type 'a résultat = Trouvé of 'a | Pas_trouvé;;

type 'a résultat = Trouvé of 'a | Pas_trouvé # let rec cherche elt liste =

match liste with

| tete :: reste when tete = elt -> Trouvé tete

| tete :: reste when tete <> elt -> cherche elt reste | _ -> Pas_trouvé;;

val cherche : 'a -> 'a list -> 'a résultat = <fun> # cherche Noir [Noir; Lait];;

- : chocolat résultat = Trouvé Noir

# cherche 0 [1; 2; 3; 4];;

(12)

Fonctions d'ordre supérieur

Des fonctions qui prennent en argument

d'autres fonctions

– utile pour être générique

# List.filter;;

- : ('a -> bool) -> 'a list -> 'a list = <fun> # List.filter (fun x -> x = 2) [1; 2; 3; 4];; - : int list = [2]

# List.filter (fun x -> x mod 2 = 0) [1; 2; 3; 4];; - : int list = [2; 4]

# List.filter (fun x -> x >= 2 && x < 4) [1; 2; 3; 4];; - : int list = [2; 3]

(13)

Style fonctionnel

Utiliser des fonctions récursives

– variables à assignation unique

on leur donne une seul valeur : let x = ... in ....

factorielle : n! = 1 * 2 * ... * n-1 * n

# let rec factorielle x =

if x <= 1 then 1 else x * factorielle (x - 1);; val factorielle : int -> int = <fun>

# factorielle 5;; - : int = 120

(14)

Style impératif

Comme la programmation « classique »

– variables peuvent être modifiées plusieurs fois

# let factorielle n =

let result = ref 1 in for i = 2 to n do

result := i * !result done;

!result;;

val factorielle : int -> int = <fun> # factorielle 5;;

(15)

Remarques sur le style fonctionnel

C'est efficace ?

– Oui car :

● une fonction récursive terminale est équivalente à

une boucle

– et le compilateur OCaml fait la transformation (comme gcc)

● en sous-main, on a un jeu de pointeur, pas de copie

réelle de données

Avantages : fonctionnel ou impératif ?

– cela dépend :-)

– le style fonctionnel permet souvent une

(16)

Programme récursif terminal

# let factorielle x = let rec f x acc =

if x <= 1 then acc else f (x - 1) (x * acc) in f x 1;;

val factorielle : int -> int = <fun> # let factorielle n =

let result = ref 1 in for i = 2 to n do

result := i * !result done;

!result;;

val factorielle : int -> int = <fun> # let rec factorielle x =

if x <= 1 then 1 else x * factorielle (x - 1);; val factorielle : int -> int = <fun>

●Fonctionnel

●Fonctionnel

terminal

(17)

Exemple de programme fonctionnel

# let rec tri liste =

match liste with | [] -> []

| x :: l -> insère x (tri l) and insère elem liste = match liste with

| [] -> [elem] | x :: l ->

if elem < x then elem :: x :: l else x :: insère elem l;; val tri : 'a list -> 'a list = <fun>

val insère : 'a -> 'a list -> 'a list = <fun> # tri [2; 1; 0];;

(18)

Style objet

Comme en C++, Java, ...

– méthodes privées/publiques, virtuelles, ... – héritage multiple

– liaison tardive – ...

Avec en plus

– objets immédiats (objet sans classe) – méthodes polymorphes

(19)

Exemple de programme objet

# class point = object val mutable x = 0 method get_x = x method move d = x <- x + d end;; class point :

object val mutable x : int method get_x : int method move : int -> unit end

# let p = new point;; val p : point = <obj> # p#get_x;; - : int = 0 # p#move 3;; - : unit = () # p#get_x;; - : int = 3

(20)

Exceptions

Comme en C++, Java, ...

– mais efficace

– donc utilisable comme structure de contrôle, pas

seulement sur les cas d'erreur

# exception Trouvé_à_l'index of int;; exception Trouvé_à_l'index of int

# let cherche x tableau =

for i = 0 to Array.length tableau - 1 do

if tableau.(i) = x then raise (Trouvé_à_l'index i) done;;

val cherche : 'a -> 'a array -> unit = <fun> # cherche 3 [|1; 4; 3; 7; 8|];;

(21)

Ramasse miettes

Récupération automatique de la mémoire

ramasse miettes, Garbage Collector (GC)

On alloue des variables, fonctions, ...

– ... la libération est automatique – pas de segfault

● toute une classe de bugs en moins !

Ramasse miettes efficace

– contrairement à Java (du moins au début)

– techniquement : GC générationnel incrémental

● générationnel : vieux objets et petits nouveaux

(22)

Compilation

Deux compilateurs

– byte code sur une machine virtuelle (ocamlc)

marche sur toutes les plate-formes ● efficace

● utilisé dans l'environnement interactif

– code natif (ocamlopt)

● pour x86, IA64, PowerPC, AMD64, Alpha, SPARC,

MIPS, PA-RISC, StrongARM

● très efficace

Plate-formes supportées

– Unix (Linux, *BSD, propriétaires), Windows,

(23)

Performances

langage score 1 C Intel 92,26 2 C gcc 85,99 3 OCaml 76,52 4 Ada 95 GNAT 63,49 ... ... ... 8 C++ Intel 44,67 ... ... ... 13 C# Mono 34,25 ... ... ... 18 Python 29,59 19 Perl 27,92 20 Tcl 26,47 21 Java 22,07 22 Ruby 18,15 ... ... ... 24 PHP 15,15

shootout.alioth.debian.org

CPU : x1 Mem : x1 Lignes : x0

OCaml est très efficace

– « au pire, 2 fois plus lent que le C »

– en pratique, quasiment aussi rapide que le C

● voire plus (gain sur

(24)

Calcul scientifique

Sieve primes up to 10^8 (bit-twiddling/array limited):

32-bit OCaml: 7.102s 32-bit C++: 19.145s

64-bit OCaml: 5.697s 64-bit C++: 13.433s

100th-nearest neighbours from a 10k-atom model of amorphous silicon (de/allocation limited):

32-bit OCaml: 28.407s 32-bit C++: 14.035s

64-bit OCaml: 35.538s 64-bit C++: 12.392s

Generate, bubble sort and accumulate an array of 10^4 double-precision random floating-point numbers:

32-bit OCaml: 1.185s 32-bit C++: 1.471s

64-bit OCaml: 0.785s 64-bit C++: 0.957s

without bounds checking:

32-bit OCaml: 0.992s 32-bit C++: 1.249s

64-bit OCaml: 0.591s 64-bit C++: 0.705s

2048^2 mandelbrot (float-arithmetic limited):

32-bit OCaml: 2.946s 32-bit C++: 1.479s

64-bit OCaml: 1.704s 64-bit C++: 1.161s

1024 FFTs and iFFTs (float-arithmetic limited):

32-bit OCaml: 31.491s 32-bit C++: 8.441s

64-bit OCaml: 9.260s 64-bit C++: 8.562s

Accumulate a Lorentzian over the number of integer triples (i, j, k) which lie in i^2 + j^2 + k^2 < 400 (float-arithmetic limited):

32-bit OCaml: 16.329s 32-bit C++: 8.002s

64-bit OCaml: 9.459s 64-bit C++: 5.933s

Jon Harrop / 2005-03-30 / caml-list

(25)

Utilisation d'OCaml

A éviter en OCaml

– programmation système et temps réel dur – boucles bien tassées

● C, C++, Ada

– petits scripts, traitement du texte, bidouille

● Perl, Python, shell script

programmation objet « pure » (à mon avis)

● C++, SmallTalk, Eiffel, Python

Pour tout le reste, OCaml est utilisable

(26)

Environnement

Environnement de programmation complet

– debugger, compilateurs, lex et yacc, éditeurs

(mode Emacs), threads, ...

– pleins de bibliothèques, d'exemples, ...

● The Hump : http://caml.inria.fr/cgi-bin/hump.en.cgi

Communauté à croissance exponentielle

– liste de diffusion (très) active

● voire trollesque

(27)

Ce dont je ne parlerai pas

Modules fonctionnels (functors)

– encapsulation et abstraction des données

Liaison avec le langage C

Labels

Debugger avec retour arrière temporel

Évaluation paresseuse

# let f ~grand ~petit = grand - petit;;

val f : grand:int -> petit:int -> int = <fun> # f ~grand:3 ~petit:2;;

- : int = 1

# f ~petit:2 ~grand:3;; - : int = 1

(28)

Et les inconvénients !?

Langage de recherche

– plus difficile de trouver un programmeur – le langage évolue (mais en bien :-)

Pas autant de bibliothèques que Java ou C

Pas de debugger sur le code natif

Messages d'erreur parfois cryptiques

Quelques contraintes liées au typage

– pas de récursivité entre modules, ordre des

(29)

un exemple : demexp

Programme OCaml complet

– réseau, serveur, client graphique (GTK2), XML,

threads

– ~10.000 lignes de source

– ~6.000 lignes de code OCaml

● ½ serveur, ½ client

– versions Linux et Windows – 2 ans de développement

Bibliothèques externes

(30)

Conclusion

OCaml a de réelles qualités

– efficace, sûr, agréable, bien outillé, portable – on évite des bugs par construction

c'est un vrai plaisir de programmer avec

● aussi rapide que le C, aussi sûr que l'Ada, aussi

souple que le Lisp (voire plus que les trois :-)

(31)

Pour démarrer

Site officiel

– http://caml.inria.fr/

– listes de discussions, sources, pointeurs

Un livre

– http://www.pps.jussieu.fr/Livres/ora/DA-OCAML/index.html – apprendre le langage ●

La bosse du chameau

– http://caml.inria.fr//cgi-bin/hump.fr.cgi – trouver la roue

(32)

Questions ?

Références

Documents relatifs

Remerciements : les auteurs remercient le CEA Marcoule pour son soutien, et en particulier Frédérick Lamare, l’archiviste du centre ; Jean-Marc Cavedon, Directeur de la

– la source de document multimédia composé: un composant doit permettre d'obtenir une description du document multimédia à adapter; dans certains cas, cette description est le

Pour comprendre les évolutions récentes et les conflits au sein des compagnies classiques, il est nécessaire de saisir que ce n’est pas seulement le concept un peu abstrait de «

Cette scène d’ouverture lors de laquelle Lori a ses règles évoque sans le dire une des plus anciennes mises en scène du problème du savoir, c’est-à-dire le récit biblique

À travers une lecture philosophique du poème Ulysse de Fondane et une analyse de ce qu’il nomme, dans Baudelaire et l’expérience du gouffre, « l’Esthétique d’Ulysse »,

We quantify the transmitting power needed for different kinds of environments (urban, rural) and frequencies and we show that the transmitting power can be optimized according

Après des accrochages autour du b ru it dès le premier jour (fête après le déménagement), Monsieur Lefranc va utiliser ces petits incidents ainsi que quelques

La conduite de U2000 et de U3M illustre donc à la fois la place croissante donnée aux collectivités locales et aux intérêts privés dans l’action publique, le déplacement des lieux