ML (γλώσσα προγραμματισμού)

Η **ML** είναι μια συναρτησιακή γλώσσα προγραμματισμού γενικής χρήσης, που αναπτύχθηκε από τον Ρόμπιν Μίλνερ και άλλους στο τέλος της δεκαετίας του 1970 στο πανεπιστήμιο του Εδιμβούργου. Ξεκίνησε ως μέτα-γλώσσα (εξού και το όνομα Meta-Language) για διαδραστικές αποδείξεις στο σύστημα Edinburgh LCF (τα αρχικά για "Logic for Computable Functions" - λογική για υπολογίσιμες συναρτήσεις) και εξελίχθηκε σε γενικής χρήσης γλώσσα προγραμματισμού για να καλύψει τις ανάγκες αυτής της εφαρμογής.

Τα συναρτησιακά στοιχεία της γλώσσας είναι εμπνευσμένα από την ISWIM και την GEDANKEN, αλλά διαφέρει στον χειρισμό των τύπων, ενώ άλλα στοιχεία της γλώσσας είναι εμπνευσμένα από τη Lisp and την POP2. Το συγκεκριμένο σύστημα αποδείξεων του LCF ήταν το PPLambda, που είναι συνδυασμός του πρωτοβάθμιου προτασιακού λογισμού (first-order predicate calculus) και του πολυμορφικού λογισμού λάμδα με απλούς τύπους (simply-typed polymorphic lambda-calculus). Αλλά, σύμφωνα με τον Ρόμπιν Μίλνερ, σχεδόν οποιδήποτε επαγωγικό σύστημα θα είχε οδηγήσει στις ίδιες βασικές αρχές της γλώσσας.

Η ML είναι γνωστή για τη χρήση του αλγόριθμου Χίντλεϋ-Μίλνερ για την εξαγωγή τύπων (type inference), που μπορεί να συνάγει αυτόματα τους τύπους των περισσοτέρων εκφράσεων της γλώσσας, χωρίς να χρειάζεται σαφείς προσδιορισμούς τύπων από τον προγραμματιστή. Είναι μία από τις λίγες γλώσσες προγραμματισμού με αυστηρή απόδειξη ότι όλα τα προγράμματα που περνάνε τον έλεγχο τύπων, δεν έχουν σφάλματα κατά την εκτέλεση.

## Περιγραφή
Η ML συχνά αναφέρεται ως **ακάθαρτη** συναρτησιακή γλώσσα, επειδή επιτρέπει παρενέργειες, και επομένως διαδικαστικό προγραμματισμό, σε αντίθεση με αμιγώς συναρτησιακές γλώσσες όπως η Haskell. Για αυτό το λόγο λέγεται και γλώσσα προγραμματισμού μικτού προτύπου.

Χαρακτηριστικά της ML περιλαμβάνουν την στρατηγική υπολογισμού της κλήσης κατά τιμή (call-by-value), συναρτήσεις πρώτης τάξης, αυτόματη διαχείριση μνήμης με συλλογή απορριμάτων, παραμετρικό πολυμορφισμό, στατικούς τύπους, εξαγωγή τύπων (type inference), αλγεβρικούς τύπους δεδομένων (algebraic datatypes), ταίριασμα προτύπων (pattern matching) και εξαιρέσεις. Παραδείγματα αυτών των χαρακτηριστικών δίνονται παρακάτω.

Αντίθετα με τη Haskell, η ML χρησιμοποιεί πρόθυμη αποτίμηση (eager evaluation), που σημαίνει ότι όλες οι υπο-εκφράσεις μιας έκφρασης αποτιμώνται. Αποτέλεσμα είναι ότι δεν μπορούν να χρησιμοποιηθούν άπειρες λίστες *ως έχει*. Παρόλα αυτά, η οκνηρή αποτίμηση (lazy evaluation) και επομένως και οι άπειρες δομές, μπορούν να προσομοιωθούν με τη χρήση ανώνυμων συναρτήσεων.

Σήμερα υπάρχουν αρκετές γλώσσες στην οικογένεια της ML. Οι δύο κύριες διάλεκτοι είναι η Standard ML και η Caml, αλλά υπάρχουν και άλλες, όπως η F#, η Lazy ML, η οποία υποστηρίζει οκνηρή αποτίμηση και η CakeML, η οποία είναι ένα υποσύνολο της ML με τυπική σημασιολογία επιβεβαιωμένη στο HOL. Ιδέες από την ML έχουν επηρεάσει πολυάριθμες άλλες γλώσσες όπως τη Haskell, τη Cyclone και τη Nemerle.

Τα δυνατά σημεία της ML συγκεντρώνονται συνήθως στο σχεδιασμό και χειρισμό γλωσσών (μεταγλωττιστές, αναλυτές, αποδείκτες θεωρημάτων όπως το HOL και το Isabelle, κλπ), και γι'αυτό έχει χρησιμοποιηθεί αρκετά στην έρευνα γλωσσών προγραμματισμού. Ως συναρτησιακή γλώσσα επιτρέπει την εύκολη υλοποίηση διαχρονικών δομών δεδομένων. Έχει χρησιμοποιηθεί επίσης στη βιοπληροφορική, σε οικονομικά συστήματα, και άλλες εφαρμογές, αλλά εκεί πιο διαδεδομένες είναι παραλλαγές της γλώσσας όπως η OCaml.

## Παραδείγματα χαρακτηριστικών γλώσσας

### Εξαγωγή τύπων

Η ML επιτρέπει την αυτόματη εξαγωγή τύπων. Για παράδειγμα, στην παρακάτω συνάρτηση οι δηλωτές (type specifiers) είναι περιττοί:

```sml
fun increment (n:int) :int = n + 1
```


Η συνάρτηση μπορεί να γραφτεί ως εξής:

```sml
fun increment n = n + 1
```

και η γλώσσα θα εξαγάγει τον τύπο της μεταβλητής n ως ακέραιο και της συνάρτησης 
```sml
increment
```
 ως συνάρτηση από ακεραίους σε ακεραίους:

```sml
val increment = fn : int -> int
```


### Αναδρομή

Η ML υποστηρίζει και ενθαρρύνει την χρήση αναδρομικών συναρτήσεων (και αναδρομικών τύπων). Για παράδειγμα η παρακάτω συνάρτηση υπολογίζει το n παραγοντικό.


```sml
fun factorial n = 
  if n = 0 then 1
  else n * factorial (n-1);;

factorial 4;; (* Υπολογίζει 4 * 3 * 2 * 1 = 24 *)
 > val it = 24 : int
```


Επίσης υποστηρίζει αμοιβαία αναδρομή (mutual recursion). Για παράδειγμα, οι παρακάτω συναρτήσεις ελέγχουν (με μη αποδοτικό τρόπο) αν ένας μη-αρνητικός ακέραιος είναι ζυγός ή περιττός, καλώντας η μία την άλλη:

```sml
fun is_odd n = 
  if n = 0 then false
  else is_even (n-1)
and is_even n = 
  if n = 0 then true
  else is_odd (n-1)

 > val is_odd = fn : int -> bool
 > val is_even = fn : int -> bool
```


### Συναρτήσεις ως τιμές

Στην ML οι συναρτήσεις είναι τιμές, που σημαίνει ότι μπορούν να δοθούν ως *όρισμα* μίας συνάρτησης ή να επιστραφούν ως *αποτέλεσμα* μίας συνάρτησης. Μία συνάρτηση με όρισμα ή αποτέλεσμα μία άλλη συνάρτηση, λέγεται συνάρτηση ανωτέρου βαθμού.

#### Συνάρτηση ως όρισμα

Για παράδειγμα, η παρακάτω συνάρτηση παίρνει ως όρισμα μία οποιαδήποτε συνάρτηση f: \mathrm{int} \to \mathrm{int} και επιστρέφει το άθροισμα f(1) + f(2) + f(3):

```sml
fun sum_three f = (f 1) + (f 2) + (f 3)
```

Άρα, όταν την καλέσουμε για g(x) = 2x + 5 η απάντηση είναι (2 \cdot 1 + 5) + (2 \cdot 2 + 5) + (2 \cdot 3 + 5) = 27:

```sml
fun g x = 2 * x + 5;;
sum_three g;;

 > val g = fn : int -> int
 > val it = 27 : int
```


#### Συνάρτηση ως αποτέλεσμα

Για παράδειγμα, η παρακάτω συνάρτηση παίρνει ως όρισμα a, b και επιστρέφει την γραμμική συνάρτηση της μορφής f(x) = a \cdot x + b:

```sml
fun linear_fn (a, b) = 
  let fun new_fn x = a * x + b in
     new_fn
  end;;

(* Παρατηρήστε ότι ο τύπος της συνάρτησης επιβεβαιώνει
   αυτό που θέλουμε όρισμα: int * int (δηλαδή (a,b)) και
   αποτέλεσμα: int -> int (δηλαδή μία συνάρτηση). *)
 > val linear_fn = fn : int * int -> int -> int
```

Επομένως, η συνάρτηση f(x) = 3x + 1, μπορεί να οριστεί ως εξής:

```sml
val threeXplusOne = linear_fn (3, 1);;
threeXplusOne 10;;
 > val threeXplusOne = fn : int -> int
 > val it = 31 : int
```

Καθώς η ML χρησιμοποιεί currying (δηλαδή όλες οι συναρτήσεις μετατρέπονται ώστε να έχουν ένα όρισμα), η 
```sml
linear_fn
```
 μπορεί να γραφτεί πιο σύντομα ως:

```sml
fun linear_fn (a, b) x = a * x + b;;
```


### Ανώνυμες συναρτήσεις

Οι συναρτήσεις μπορούν να οριστούν και ως ανώνυμες. Δηλαδή στο παραπάνω παράδειγμα, στην κλήση στο 
```sml
sum_three
```
:

```sml
fun g x = 2 * x + 5;;
sum_three g;;
```

θα μπορούσε να χρησιμοποιηθεί μία ανώνυμη στην θέση της g, ως εξής:

```sml
sum_three (fn x => 2 * x + 5)
```

Με αυτόν τον τρόπο αποφεύγεται η ονομασία απλών συναρτήσεων και μειώνονται οι γραμμές κώδικα. 

### Παραμετρικός πολυμορφισμός

Η ML επιτρέπει τον παραμετρικό πολυμορφισμό, δηλαδή τον ορισμό γενικών συναρτήσεων και γενικών τύπων, που δουλεύουν για όλους τους δυνατούς τύπους της παραμέτρου.

#### Παράδειγμα 1ο: Απλές συναρτήσεις

Η πιο απλή τέτοια συνάρτηση είναι η ταυτοτική συνάρτηση

```sml
fun id x = x
```

η οποία έχει τύπο 

```sml
val id = fn : 'a -> 'a
```

To 
```sml
'a
```
 είναι η παράμετρος και ο τύπος 
```sml
'a -> 'a
```
 υποδηλώνει ότι συνάρτηση παίρνει ένα στοιχείο οποιοδήποτε τύπου και επιστρέφει ένα στοιχείο του ίδιου τύπου (στην συγκεκριμένη περίπτωση και το ίδιο στοιχείο). Αυτό μας επιτρέπει να γράψουμε:

```sml
id 3;;
 > val it = 3 : int
id 3.0;;
 > val it = 3.0 : real
id "Hello";;
 > val it = "Hello" : string
```


Μία λίγο πιο σύνθετη συνάρτηση είναι αυτή που αντιστρέφει τις τιμές ενός ζεύγους, π.χ. για είσοδο 
```sml
(10, "hello")
```
 επιστρέφει 
```sml
("hello", 10)
```
. Αυτή μπορεί να οριστεί ως εξής:

```sml
fun swap (x, y) = (y, x);;
 > val swap = fn : 'a * 'b -> 'b * 'a
```

Ο τύπος 
```sml
'a * 'b -> 'b * 'a
```
 σημαίνει ότι η συνάρτηση παίρνει ως όρισμα ένα ζεύγος τύπου 
```sml
'a * 'b
```
 (π.χ. για το 
```sml
(10, "hello")
```
, ο τύπος είναι 
```sml
string * int
```
) και επιστρέφει ένα ζεύγος τύπου 
```sml
'b * 'a
```
 (το 
```sml
("hello", 10)
```
 με τύπο 
```sml
int * string
```
).

#### Παράδειγμα 2ο: Map

Μία πιο σύνθετη συνάρτηση που χρησιμοποιείται αρκετά συχνά είναι η 
```sml
map
```
. Αυτή επιτρέπει την εφαρμογή μία συνάρτησης σε κάθε στοιχείο μίας λίστας. Για παράδειγμα, 

```sml
(* Προσθέτει +10 σε κάθε αριθμό της λίστας *)
map (fn x => x + 10) [1, 6, 2, 7, 8];;
 > val it = [11,16,12,17,18] : int list
(* Επισημαίνει ποιοι από τους αριθμούς είναι ζυγοί *)
map (fn x => x mod 2 = 0) [1, 5, 2, 7, 8];;
 > val it = [false,false,true,false,true] : bool list
map (fn x => if x then "Even" else "Odd") [false,false,true,false,true];;
 > val it = ["Odd","Odd","Even","Odd","Even"] : string list
```


Η συνάρτηση 
```sml
map
```
 μπορεί να οριστεί ως εξής:

```sml
fun map f [] = []
|   map f (x::xs) = (f x)::map f xs;;
 > val map = fn : ('a -> 'b) -> 'a list -> 'b list
```

Ο τύπος της δηλώνει ότι δέχεται μία συνάρτηση τύπου 
```sml
'a -> 'b
```
 (για παράδειγμα 
```sml
fn x => x mod 2 = 0
```
 που ελέγχει αν ο x είναι ζυγός) και μία λίστα τύπου 
```sml
'a list
```
 (π.χ. μία λίστα ακεραίων) και επιστρέφει μία λίστα  τύπου 
```sml
'b list
```
 (π.χ. μία λίστα από booleans).

Παρόμοιες συναρτήσεις είναι η 
```sml
filter
```
, 
```sml
exists
```
, 
```sml
foldr
```
.

#### Παράδειγμα 3ο: Σύνθεση συναρτήσεων

Μπορούμε να ορίσουμε μία συνάρτηση που συνθέτει δύο συναρτήσεις ως εξής:

```sml
fun compose f g x = f ( g x )
 > val compose = fn : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b
```


Άρα για την σύνθεση της f(x) = 2x + 1 και της g(x) = x^2 + 2 (που έχει ως αποτέλεσμα την h(x) = f(g(x)) = 2 \cdot (x^2 + 2) + 1 = 2x^2 + 5), γράφουμε: 

```sml
val h = compose (fn x => 2 * x + 1) (fn x => x * x + 2)
h 10 (* Επιστρέφει 2 * 10^2 + 5 *)
```


Άλλη μία εφαρμογή της 
```sml
compose
```
 είναι η συγχώνευση δύο map. Στο προηγούμενο παράδειγμα τα δύο τελευταία map μπορούν να αντικατασταθούν με ένα:

```sml
map (compose (fn x => if x then "Even" else "Odd") (fn x => x mod 2 = 0)) [1, 5, 2, 7, 8]
 > val it = ["Odd","Odd","Even","Odd","Even"] : string list
```


### Αλγεβρικός τύπος δεδομένων

Η ML υποστηρίζει τον ορισμό καινούργιων αλγεβρικών τύπων δεδομένων.

Στην πιο απλή περίπτωση, αυτοί μπορεί να είναι απαριθμητικοί τύποι, π.χ. οχήματα:

```sml
datatype Vehicle = Bicycle | Car | Truck;;
fun vehicle_to_str Bicycle = "bicycle"
|   vehicle_to_str Car = "car"
|   vehicle_to_str Truck = "truck";;
 > val vehicle_to_str = fn : Vehicle -> string
vehicle_to_str Truck;;
 > val it = "truck" : string
```


Στην λίγο πιο σύνθετη μορφή, κάποιοι από τους τύπους μπορούν να έχουν παραπάνω πληροφορίες. Άμα θέλαμε για τα οχήματα να ξέρουμε και πόσες ρόδες έχουν, τότε θα αλλάζαμε τα φορτηγά ώστε:

```sml
(* Θεωρούμε ότι το ποδήλατο έχει 2 και το αυτοκίνητο 4 ρόδες. 
   Τα φορτηγά μπορεί να έχουν 6, 8, 10 ή και παραπάνω ρόδες, επομένως 
   πρέπει να επισημανθεί ο αριθμός όταν το ορίζουμε. *)
datatype VehicleWithWheels = Bicycle | Car | Truck of int;;

fun vehicle_to_str Bicycle = "bicycle has 2 wheels" 
|   vehicle_to_str Car = "car has 4 wheels"
|   vehicle_to_str (Truck n) = "truck has " ^ Int.toString n ^ " wheels";;
 > val vehicle_to_str = fn : VehicleWithWheels -> string
vehicle_to_str (Truck 10);;
 > val it = "truck has 10 wheels" : string
```

Οι τύποι αυτοί μπορεί να είναι και αναδρομικοί. Για παράδειγμα ο παρακάτω τύπος επιτρέπει τον ορισμό αριθμητικών παραστάσεων:

```sml
datatype Expression = 
  Num of int 
| Neg of Expression
| Plus of Expression * Expression 
| Mult of Expression * Expression;;
```

και η παρακάτω συνάρτηση επιτρέπει τον υπολογισμό τους.

```sml
fun evaluate (Num n) = n
|   evaluate (Neg e) = ~(evaluate e)
|   evaluate (Plus (e1, e2)) = (evaluate e1) + (evaluate e2)
|   evaluate (Mult (e1, e2)) = (evaluate e1) * (evaluate e2);;
 > val evaluate = fn : Expression -> int
 
(* Υπολογισμός της παράστασης: 10 + 5 * (7 - 3) = 30. *)
evaluate (Plus(Num 10, Mult(Num 5, Plus(Num 7, Neg(Num 3)))));;
 > val it = 30 : int
```


Οι τύποι μπορεί να είναι και πολυμορφικοί. Για παράδειγμα, ένας τύπος για λίστες μπορεί να οριστεί ως εξής:

```sml
datatype 'a MyList = Empty | Item of 'a * 'a MyList
```

και συναρτήσεις όπως η 
```sml
length
```
, για την εύρεση του μήκους μίας λίστας, μπορούν να οριστούν ως εξής:

```sml
(* Συνάρτηση που επιστρέφει το μήκος της λίστας. *)
fun length Empty = 0
|   length (Cons(x, t)) = 1 + length t;;
 > val length = fn : 'a MyList -> int

(* Ορισμός μίας λίστας με τα στοιχεία 10, 20 και 30. *)
val ls = Cons(10, Cons(20, Cons(30, Empty)));;
length ls;;
 > val it = 3 : int
```

Αντίστοιχα με τις λίστες, μπορούν να οριστούν και άλλες δομές, όπως τα δυαδικά δένδρα:

```sml
datatype 'a BTree = Leaf | Branch of 'a * ('a BTree) * ('a BTree)
```


### Άπειρες δομές

#### Άπειρες λίστες

Ο ορισμός αναδρομικών δομών και η δυνατότητα της αναπαράστασης των συναρτήσεων ως τιμές, επιτρέπει την αναπαράσταση λιστών με άπειρο μέγεθος. Ένας συνηθισμένος τρόπος είναι ο εξής:

```sml
(* Κάθε ένα κομμάτι της λίστας έχει ένα στοιχείο (τύπου 'a) 
   και μία συνάρτηση που όταν την καλέσουμε επιστρέφει 
   αναδρομικά την υπόλοιπη λίστα. *)
datatype 'a LazyList = Cons of 'a * (unit -> 'a LazyList)
```

Για παράδειγμα, η άπειρη ακολουθία ακεραίων ίσων ή μεγαλύτερων του n, ορίζεται ως εξής:

```sml
fun integers_from n = 
   Cons(n, fn () => integers_from (n+1));;
```

Τα πρώτα n στοιχεία της λίστας μπορούν να ανακτηθούν ως εξής:

```sml
fun get_first _ 0 = []
|   get_first (Cons(x, t)) n = x::(get_first (t()) (n-1));;
 > val get_first = fn : 'a LazyList -> int -> 'a list
(* Επιστρέφει τους ακεραίους 1, 2, ... , 10. *)
get_first (integers_from 1) 10;;
 > val it = [1,2,3,4,5,6,7,8,9,10] : int list
```


Χρησιμοποιώντας αντίστοιχες συναρτήσεις με αυτές που υπάρχουν για λίστες (όπως η 
```sml
map
```
), μπορούμε να ορίσουμε πιο σύνθετες ακολουθίες όπως τους ζυγούς αριθμούς ή τα τετράγωνα αριθμών:

```sml
(* Map για άπειρες λίστες. *)
fun lazy_list_map f (Cons(x, t)) =
   Cons(f x, fn () => lazy_list_map f (t()));;

(* Επιστρέφει μία ακολουθία με τους ζυγούς φυσικούς αριθμούς. *) 
val even_naturals = lazy_list_map (fn x => 2 * x) (integers_from 0);;
(* Επιστρέφει τους πρώτους 10 ζυγούς: 0, 2, ... , 18. *)
get_first even_naturals 10;;
 > val it = [0,2,4,6,8,10,12,14,16,18] : int list

(* Επιστρέφει μία ακολουθία με τα τετράγωνα αριθμών. *) 
val squares = lazy_list_map (fn x => 2 * x) (integers_from 0);;
(* Επιστρέφει τα 4 πρώτα τετράγωνα: 0, 1, 4, 9. *)
get_first squares 4;;
 > val it = [0,2,4,6] : int list
```


#### Άπειρα δυαδικά δένδρα

Αντίστοιχα με τις άπειρες λίστες μπορούν να οριστούν άπειρα δυαδικά δένδρα, π.χ. ως εξής:

```sml
datatype 'a LazyBTree = Branch of 'a * (unit -> 'a LazyBTree) * (unit -> 'a LazyBTree)
```


### Ταίριασμα προτύπων

Η ML επιτρέπει το ταίριασμα προτύπων. Για παράδειγμα, την συνάρτηση 
```sml
factorial
```
, μπορούμε να την γράψουμε ως εξής:

```sml
(* 1η Εκδοχή με την χρήση case ...  of *)
fun factorial n = case n of 
   0 => 1
|  n => n * factorial (n-1)

(* 2η Εκδοχή *)
fun factorial 0 = 1
|   factorial n = n * factorial (n-1)
```

Ο έλεγχος των προτύπων γίνεται με την σειρά που δίνονται οι περιπτώσεις. Επομένως, αν στην 
```sml
factorial
```
 αλλάξουμε την σειρά των περιπτώσεων, τότε το n θα ταιριάζει όλους τους ακεραίους και η δεύτερη περίπτωση δεν εκτελείται ποτέ. Αυτό οδηγεί στο σφάλμα 
```console
Error: match redundant
```
. Αντίστοιχα αν δεν καλύπτονται όλες οι περιπτώσεις, εμφανίζεται η προειδοποίηση 
```console
Warning: match nonexhaustive
```
.

```sml
fun factorial n = n * factorial (n-1)
|   factorial 0 = 1;;
 > stdIn: Error: match redundant
          n => ...
    -->   0 => ...

fun factorial 0 = 1;;
 > stdIn: Warning: match nonexhaustive
          0 => ...
```


### Εξαιρέσεις

Η ML υποστηρίζει εξαιρέσεις. Με την σύνταξη 
```console
raise <exception>
```
 εγείρεται μία εξαίρεση και με το 
```console
handle <exception pattern> => <expression>
```
 διαχειρίζεται μία εξαίρεση. Για την συνάρτηση 
```sml
factorial
```
 που ορίσαμε παραπάνω, για αρνητικούς αριθμούς μπορούμε να εγείρουμε μία εξαίρεση ως εξής:


```sml
fun factorial n =
  if n = 0 then 1
  else if n > 0 then n * factorial (n-1)
  else raise Fail "Factorial only defined for non-negative integers."
(* Παρατηρήστε ότι ο τύπος της συνάρτησης δεν αλλάζει. *)
 > val factorial = fn : int -> int
```

Επομένως, άμα την καλέσουμε με αρνητικό ακέραιο, παίρνουμε:

```console
factorial (~2)
 > uncaught exception Fail [Fail: Factorial only defined for non-negative integers.]
```

Εκτός από τις εξαιρέσεις της γλώσσας (Overflow, Div, Domain, Chr, Subscript), επιπλέον εξαιρέσεις μπορούν να οριστούν από τον χρήστη:

```sml
(* Εξαίρεση ειδικά ορισμένη για την συνάρτηση factorial. *)
exception FactorialException of string;;

fun factorial n =
  if n = 0 then 1
  else if n > 0 then n * factorial (n-1)
  else raise FactorialException "Given a negative integer.";;
  
factorial (~2);;
 > uncaught exception FactorialException
```


Ο παρακάτω κώδικας είναι ένα παράδειγμα διαχείρισης μίας εξαίρεσης:

```sml
(* Συνάρτηση που δέχεται μία λίστα και επιστρέφει 0 αν η λίστα είναι άδεια,
   διαφορετικά το παραγοντικό του πρώτου στοιχείου (και 1 αν είναι αρνητικός αριθμός). *)
fun hd_factorial ls = factorial (hd ls)
  handle Empty => 0
  |      _ => 1;;

hd_factorial [3, 1, 2];;
 > val it = 6 : int
hd_factorial [~2, 1, 3];;
 > val it = 1 : int
hd_factorial [];;
 > val it = 0 : int
```


Οι εξαιρέσεις μπορούν να χρησιμοποιηθούν και για την υλοποίηση της οπισθοδρόμησης.

### Πράξεις με παρενέργειες

Η ML έχει πράξεις με παρενέργειες, όπως είναι η δήλωση ανάθεσης 
```sml
:=
```
,

```sml
val a = ref 10;;
 > val a = ref 10 : int ref
a := !a + 5;;
 > val it = () : unit
a;;
 > val it = ref 15 : int ref
```


## Δείτε επίσης
* OCaml

## Εξωτερικοί σύνδεσμοι

**Σελίδες υποστήριξης των εκδόσεων της ML:**
* Standard ML of New Jersey
* Standard ML Family GitHub Project
* Poly/ML
* Moscow ML
* MLton
**Βιβλία:**
* ML for the Working Programmer
* Elements of ML Programming
* Purely Functional Data Structures, Βιβλίο για την υλοποίηση δομών δεδομένων στην ML (και γενικά σε συναρτησιακές γλώσσες).
* Programming With Standard ML
* The Little MLer
* Commentary on Standard ML
**Tutorial:**
* Four Lectures on Standard ML
* A gentle introduction to SML 
* Programming in Standard ML
* Notes on Programming Standard ML of New Jersey
* Programming in Standard ML ’97: A Tutorial Introduction
**Πανεπιστημιακά μαθήματα:**
* Γλώσσες Προγραμματισμού Ι, Διαλέξεις 4-5
* Γλώσσες Προγραμματισμού Ι: Βιντεομάθημα  Ενότητες 4-6
* Foundations of Computer Science, Εισαγωγή στην πληροφορική με ML.
* Principles of Programming, Εισαγωγή στον προγραμματισμό με ML.

## Παραπομπές


Κατηγορία:Συναρτησιακές γλώσσες προγραμματισμού