Vai alla Home Page About me Courseware Federica Living Library Federica Federica Podstudio Virtual Campus 3D Le Miniguide all'orientamento Gli eBook di Federica La Corte in Rete
 
 
Il Corso Le lezioni del Corso La Cattedra
 
Materiali di approfondimento Risorse Web Il Podcast di questa lezione

Aniello Murano » 19.Un linguaggio Eager: il Linguaggio OCaml


OCaml

  • Objective Caml (OCaml) è un linguaggio avanzato di programmazione appartenente alla famiglia di linguaggi di programmazione ML:
    • L’acronimo ML identifica il linguaggio di programmazione funzionale general-purpose sviluppato dall’equipe di Robin Milner presso l’Università di Edimburgo alla fine degli anni ‘70.
  • OCaml condivide le caratteristiche dei linguaggi funzionali e di quelli imperativi, ma contiene elementi di programmazione orientata agli oggetti e alcune differenze sintattiche.
  • Si distingue dagli altri linguaggi della famiglia ML per le prestazioni:
    • Il sistema di run-time è stato progettato per essere veloce ed efficiente e per avere poche richieste di memoria.
  • OCaml è sviluppato e distribuito come software open source dalla INRIA nel 1996 da Xavier Leroy e Jerome Vouillon come successore del CAML.

Da Caml a OCaml

  • CAML (Categorical Abstract Machine Language) è una versione di ML sviluppata in Francia presso l’INRIA e l’ Ecole Normale Superieure (ENS).
  • La sua prima implementazione, in LISP, è stata soprannominata Heavy CAML per la richiesta di ingenti risorse computazionali.
  • Il suo successore è CAML Light, implementato in C da Xavier Leroy and Damien Doligez.
    • CAML Light aggiunge al precedente nucleo del linguaggio un potente sistema di modularizzazione.
  • Dal 1996, è stato aggiunto anche il trattamento degli oggetti e da allora il nome del linguaggio è mutato in Objective Caml.

Caratteristiche di Ocaml (1)

OCaml è un linguaggio prevalentemente funzionale.

  • Un programma in OCaml può essere visto come la definizione di un insieme di funzioni che si possono richiamare l’un l’altra ricorsivamente.
  • Le funzioni di base sono trattate come “oggetti di prima classe”, a partire dai quali è possibile definire “funzioni di ordine superiore”, cioè funzioni che prendono funzioni come argomento o che restituiscono funzioni in uscita.

Caratteristiche di Ocaml (2)

OCaml è un linguaggio interattivo.

  • Ogni espressione in input viene analizzata sintatticamente, compilata e valutata (eseguita);
  • Il risultato della valutazione viene restituito, insieme al suo tipo.

OCaml è fortemente e staticamente tipato.

  • Ogni espressione ben formata ha un tipo che descrive l’insieme di valori a cui essa può essere valutata;
  • Il tipo di un’espressione viene determinato automaticamente a tempo di compilazione.

OCaml, dunque, utilizza una tecnica di valutazione eager (caratteristica dei linguaggi ML e LISP).

  • Gli argomenti sono valutati prima della chiamata a funzione (Call by Value).

Caratteristiche di Ocaml (3)

  • OCaml ha un meccanismo di pattern matching (controllo della presenza di componenti di un determinato pattern), utile per:
    • implementare funzioni definite per casi;
    • destrutturare dati complessi ed estrarne le componenti.
  • OCaml ha un sistema di tipi polimorfo:
    • è possibile definire facilmente strutture dati (liste o alberi) che possono contenere elementi di tipo diverso (ma tutti gli elementi ciascuna struttura devono essere dello stesso tipo);
    • una stessa funzione può essere applicata a tipi differenti (ad esempio, una stessa funzione per ordinare liste di interi e stringhe).
  • OCaml permette di definire con facilità nuovi tipi attraverso la definizione dei loro valori usando opportuni costruttori.

I compilatori di OCaml

  • OCaml fornisce due compilatori:
    • ocamlc, che compila in bytecode ed è indipendente dalla macchina ospite;
    • ocamlopt, che compila in codice macchina nativo ottimizzato.
  • Per compilare un singolo file occorre usare:

ocamlc -c <file>.ml

In questo caso il file sorgente deve avere il suffisso .ml e la compilazione produce un file con suffisso .cmo.

  • La compilazione con ocamlopt produce file con estensione .cmx.

Espressioni

  • Nel prompt di OCaml, contraddistinto dal simbolo di cancelletto (#), è possibile inserire espressioni (su uno o più righe), le quali saranno subito valutate dall’interprete, che ne stamperà il tipo (dedotto automaticamente) e il valore.
  • Le espressioni terminano con due “punto e virgola” consecutivi. Ad esempio:

# 3 + 3 ; ; 

- : int = 6

Variabili

Una variabile viene introdotta nell’ambiente legandola ad un valore (value binding), per mezzo della sintassi:

let Variabile = Espressione

  • OCaml valuta prima la parte destra dell’equazione e poi ne lega il valore alla variabile specificata nella parte sinistra.
  • I nomi delle variabili devono essere scritti minuscolo.

# let n = 2 + 3 ; ;

val n : int = 5

  • Il valore di una variabile è definito dal let più recente.

Il sistema di tipi

  • In OCaml è possibile distinguere fra due categorie di tipi:
    • tipi base;
    • tipi composti , i cui oggetti sono decomponibili in oggetti più semplici, di tipo base o anch’esso composto.

Tipi base (1)

  • I tipi base sono i seguenti:
    • bool: consiste dei valori true e false.
      • OCaml fornisce i classici operatori per manipolare valori booleani:

# not true ; ; 

- : bool = false

  • Int:
    • è l’insieme dei numeri interi positivi e negativi

# 24 ; ; 

- : int = 24

 

Tipi base (2)

  • float:
    • consiste nell’insieme dei numeri floating point.
    • OCaml fornisce operatori aritmetici e relazionali e funzioni di conversione fra reali ed interi.

# 3. 14 ; ;                
 # 3 . 0==1.0 ; ;
- : float = 3 . 14     
- : bool = false

  • char
    • consiste nell’insieme dei caratteri ASCII.
    • OCaml fornisce funzioni per convertire caratteri in interi, corrispondenti al loro codice ASCII, e viceversa:

# ‘q’ ; ;

- : char = ‘q’

# ‘120′ ; ; 

- : char = ‘x’

Tipi composti

  • I tipi composti vengono ottenuti a partire da altri tipi (base o composti):
    • string:
      • consiste nell’insieme delle stringhe di caratteri.
      • È possibile concatenare stringhe, estrarne caratteri e rimpiazzarli.

# “pippo” ; ;

# “pippo”^” pluto e “^”papaerino” ; ;

- : string = “pippo”

- : string = “pippo pluto e paperino”

  • records:
    • consistono in insiemi finiti di campi etichettati con un nome ad ognuno dei quali corrisponde un valore di un tipo arbitrario.

# type scheda = { nome : string; indirizzo: string; salario: float}; ;

type scheda = { nome : string; indirizzo: string; salario : float; }

  • arrays:
    • sono vettori di valori di lunghezza fissata, dove tutti i valori devono avere lo stesso tipo.

# let a = [ |1; 3; 5; 7|] ; ;
val a : int array = [ |1;   3;   5;   7|]

Funzioni (1)

  • Un programma OCaml è essenzialmente un insieme di definizioni di funzioni, che vengono definite mediante la keyword fun:

# fun x – > 2 * x ; ;
- : int – > int = <fun>

  • Le funzioni sono first class objects:
    • una funzione è un valore come un altro che:
      • Può essere costruito;
      • Passato come parametro;
      • Applicato ad argomenti.
  • Le funzioni per default non hanno nome:
    • È possibile legare una funzione ad una variabile mediate let; la variabile può essere considerata il “nome” della funzione:

# let doppio = fun x -> 2* x ; ;

val doppio : int -> int = <fun>

Funzioni (2)

  • Le funzioni hanno un solo argomento:
    • Più parametri sono passati usando una tupla, oppure mediante curryficazione.
  • La curryficazione (così chiamata in onore del logico Haskell Curry) consiste nel trasformare una funzione che prende più parametri attraverso una tupla in un’altra che può ricevere un sottoinsieme dei parametri della funzione originaria e restituire una nuova funzione, la quale può a sua volta prendere i parametri rimanenti e restituire il risultato.
  • Ad esempio, prendendo la funzione di due variabili:

function (y, x) -> y*x

e fissando y=2, si ottiene la funzione in una sola variabile:

function (x) -> 2*x

Funzioni e pattern matching (1)

  • Volendo definire una funzione che risponda in maniera differente ad input differenti, nei linguaggi tradizionali si usano le strutture if then else o case.
  • In OCaml si può sfruttare al meglio anche il pattern matching:

# let rec factorial = function

0 -> 1

| n -> n*factoril (n-1) ; ;

val factoril : int -> int = <fun>

  • Viene usato il pattern matching per isolare i vari casi dell’input e specificare il conseguente comportamento della funzione.

Funzioni e pattern matching (2)

Ovviamente la funzione factorial si può definire anche senza utilizzare il pattern matching:

# let rec factorial n =

if n = 0 then

1

else

n*factorial (n-1) ; ;

val factorial : int -> int = <fun>

Cicli for

  • OCaml supporta una forma piuttosto limitata del familiare ciclo for:

for variable =

start to end to

expression

done

  • OCaml non supporta il concetto di uscita anticipata da un loop:
    • in realtà, si potrebbe sollevare un’eccezione e farlo uscire, ma ciò sarebbe lento e rozzo.
  • I programmatori funzionali tendono ad utilizzare la ricorsione al posto dei loop espliciti, e guardano con sospetto ai cicli for, donde il motivo per cui il loop for di OCaml è relativamente impotente.

Cicli while

  • I cicli while in OCaml sono scritti:

while condizione -

boleana do

espressione

done

  • Come per i cicli for, non v’è alcun modo fornito dal linguaggio di uscire in anticipo da un ciclo while, eccetto il sollevare un’eccezione, e ciò significa che i cicli while hanno un’utilizzo abbastanza limitato.

Altre caratteristiche di OCaml

  • Altre caratteristiche di OCaml sono:
    • La Tail recursion:
    •  
      • un caso speciale di ricorsione in cui l’ultima operazione della funzione è una chiamata ricorsiva.
    • L’uso dei Functors (parametric modules):
    •  
      • costrutti che consentono di invocare o chiamare un oggetto come se si trattasse di una normale funzione, di solito con la stessa sintassi.
    • La gestione delle eccezioni;
    • Un garbage collection incrementale.
  • Contenuti protetti da Creative Commons
  • Feed RSS
  • Condividi su FriendFeed
  • Condividi su Facebook
  • Segnala su Twitter
  • Condividi su LinkedIn
Progetto "Campus Virtuale" dell'Università degli Studi di Napoli Federico II, realizzato con il cofinanziamento dell'Unione europea. Asse V - Società dell'informazione - Obiettivo Operativo 5.1 e-Government ed e-Inclusion