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

Τα συναρτησιακά στοιχεία της γλώσσας είναι εμπνευσμένα από την ISWIM και την GEDANKEN, αλλά διαφέρει στον χειρισμό των τύπων, ενώ άλλα στοιχεία της γλώσσας είναι εμπνευσμένα από τη Lisp and την POP2.:89 Το συγκεκριμένο σύστημα αποδείξεων του 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) και επομένως και οι άπειρες δομές, μπορούν να προσομοιωθούν με τη χρήση ανώνυμων συναρτήσεων.:191-211

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

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

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

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

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

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

```

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

```
fun increment n = n + 1

```

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

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

```

### Αναδρομή

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

```
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). Για παράδειγμα, οι παρακάτω συναρτήσεις ελέγχουν (με μη αποδοτικό τρόπο) αν ένας μη-αρνητικός ακέραιος είναι ζυγός ή περιττός, καλώντας η μία την άλλη:

```
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 οι συναρτήσεις είναι τιμές, που σημαίνει ότι μπορούν να δοθούν ως *όρισμα* μίας συνάρτησης ή να επιστραφούν ως *αποτέλεσμα* μίας συνάρτησης. Μία συνάρτηση με όρισμα ή αποτέλεσμα μία άλλη συνάρτηση, λέγεται συνάρτηση ανωτέρου βαθμού.

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

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

```
fun sum\_three f = (f 1) + (f 2) + (f 3)

```

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

```
fun g x = 2 \* x + 5;;
sum\_three g;;

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

```

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

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

```
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

```

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

```
val threeXplusOne = linear\_fn (3, 1);;
threeXplusOne 10;;
 > val threeXplusOne = fn : int -> int
 > val it = 31 : int

```

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

```
fun linear\_fn (a, b) x = a \* x + b;;

```

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

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

```
fun g x = 2 \* x + 5;;
sum\_three g;;

```

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

```
sum\_three (fn x => 2 \* x + 5)

```

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

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

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

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

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

```
fun id x = x

```

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

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

```

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

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

```

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

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

```

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

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

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

```
(\* Προσθέτει +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

```

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

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

```

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

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

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

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

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

```

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

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

```

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

```
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 υποστηρίζει τον ορισμό καινούργιων αλγεβρικών τύπων δεδομένων.

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

```
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

```

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

```
(\* Θεωρούμε ότι το ποδήλατο έχει 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

```

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

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

```

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

```
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

```

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

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

```

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

```
(\* Συνάρτηση που επιστρέφει το μήκος της λίστας. \*)
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

```

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

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

```

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

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

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

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

```

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

```
fun integers\_from n = 
   Cons(n, fn () => integers\_from (n+1));;

```

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

```
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

```

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

```
(\* 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

```

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

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

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

```

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

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

```
(\* 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)

```

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

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

```
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

```

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

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

```

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

```
(\* Εξαίρεση ειδικά ορισμένη για την συνάρτηση 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

```

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

```
(\* Συνάρτηση που δέχεται μία λίστα και επιστρέφει 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 έχει πράξεις με παρενέργειες, όπως είναι η δήλωση ανάθεσης `:=`,

```
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
* Γλώσσες Προγραμματισμού Ι: Βιντεομάθημα Αρχειοθετήθηκε 2022-07-18 στο Wayback Machine. Ενότητες 4-6
* Foundations of Computer Science, Εισαγωγή στην πληροφορική με ML.
* Principles of Programming, Εισαγωγή στον προγραμματισμό με ML.

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

1. 1 2 3  Gordon, Michael J. C. (1979). *Edinburgh LCF : a mechanised logic of computation*. Berlin: Springer-Verlag. ISBN 978-3-540-09724-2.
2. 1 2  Milner, R. (1982). «How ML evlolved». *ML/Hope/LCF Newsletter* **1** (1): 25-34. .
3. ↑  Gordon, M.; Milner, R.; Morris, L.; Newey, M.; Wadsworth, C. (1978). «A Metalanguage for interactive proof in LCF». *Proceedings of the 5th ACM SIGACT-SIGPLAN symposium on Principles of programming languages*: 119–130. doi:https://doi.org/10.1145/512760.512773.
4. 1 2  Milner, Robin· Tofte, Mads· Harper, Robert· MacQueen, David (1997). *The definition of standard ML : revised* (PDF). Cambridge, Mass.: MIT Press. ISBN 9780262631815.
5. ↑  Hindley, R. (1969). «The Principal Type-Scheme of an Object in Combinatory Logic». *Transactions of the American Mathematical Society* **146**: 29. doi:doi:10.2307/1995158.
6. 1 2  Milner, Robin (1978). «A theory of type polymorphism in programming». *Journal of Computer and System Sciences* **17** (3): 348-375. doi:https://doi.org/10.1016/0022-0000(78)90014-4.
7. 1 2 3 4 5 6 7 8 9 10 11 12 13  Paulson, Lawrence C. (1996). *ML for the working programmer* (2η έκδοση). Cambridge: Cambridge University Press. ISBN 978-0-521-57050-3.
8. ↑  Augustsson, L.; Johnsson Τ. (1989). «The Chalmers Lazy-ML Compiler». *The Computer Journal* **32** (2): 127–141. doi:https://doi.org/10.1093/comjnl/32.2.127. .
9. ↑  Kumar, Ramana; Myreen, Magnus O.; Norrish, Michael; Owens, Scott (2014). «CakeML: a verified implementation of ML». *ACM SIGPLAN Notices* **49** (1): 179–191. doi:https://doi.org/10.1145/2578855.2535841.
10. ↑  Appel, Andrew W. (1998). *Modern compiler implementation in ML*. Cambridge: Cambridge University Press. ISBN 0-521-60764-7.
11. ↑  Nipkow, Tobias· Wenzel, Markus· Paulson, Lawrence C. (2002). *Isabelle/HOL : a proof assistant for higher-order logic*. Berlin: Springer. ISBN 978-3-540-43376-7.
12. 1 2  Okasaki, Chris (1996). *Purely functional data structures*. Cambridge, U.K.: Cambridge University Press. ISBN 9780521663502.
13. ↑  Wong, Limsoon (2000). «The functional guts of the Kleisli query system». *ACM SIGPLAN Notices* **35** (9): 1–10. doi:https://doi.org/10.1145/357766.351241.
14. ↑  «OCaml in Industry». OCaml. Ανακτήθηκε στις 17 Ιουλίου 2022.
15. 1 2 3  Ullman, Jeffrey D. (1994). *Elements of ML programming* (ML97 έκδοση). Upper Saddle River, NJ: Prentice Hall. ISBN 9780137903870.
16. ↑  Myers, Colin· Clark, Chris· Poon, Ellen (1993). *Programming with Standard ML*. New York: Prentice Hall. ISBN 0-13-722075-8.
17. ↑  Felleisen, Matthias (1998). *The little MLer*. Cambridge, Mass.: MIT Press. ISBN 9780262561143.
18. ↑  Milner, R. (1990). *Commentary on Standard ML*. Cambridge, MA: MIT Press. ISBN 9780262631372.
19. ↑  Tofte, Mads. «Four Lectures on Standard ML» (PDF). Ανακτήθηκε στις 17 Ιουλίου 2022.
20. ↑  Cumming, Andrew. «A Gentle Introduction to ML». Ανακτήθηκε στις 17 Ιουλίου 2022.
21. ↑  Harper, Robert. «Programming in Standard ML» (PDF). Carnegie Mellon University. Ανακτήθηκε στις 17 Ιουλίου 2022.
22. ↑  Pucella, Riccardo. «Notes on Programming Standard ML of New Jersey» (PDF). Cornell University. Ανακτήθηκε στις 17 Ιουλίου 2022.
23. ↑  Gilmore, Stephen. «Programming in Standard ML '97: An On-line Tutorial» (PDF). University of Edinburgh. Ανακτήθηκε στις 17 Ιουλίου 2022.

|  |  |  |  |
| --- | --- | --- | --- |
| 

| π • σ • ε
Γλώσσες προγραμματισμού |
| --- |
|  |
| 
* Ada
* ALGOL
* APL
* Applescript
* Assembly
* BASIC
* C
* C++
* C#
* COBOL
* Erlang
* Forth
* Fortran
* Go
* Haskell
* Java
* JavaScript
* Kotlin
* Lisp
* Logo
* Lua
* ML
* Objective-C
* Pascal
* Perl
* PHP
* Prolog
* Python
* R
* Ruby
* Rust
* SQL
* Shell
* Simula
* Smalltalk
* Swift
* Visual Basic
 |

 |

|  |  |  |
| --- | --- | --- |
| 

|  |  |
| --- | --- |
| Καθιερωμένοι όροι | 
* WorldCat
* LCCN: sh87004533
* NKC: ph809012

 |

 |

|  |  |
| --- | --- |
| 

|  |
| --- |
| * Πύλη:Προγραμματισμός
 |

 |