mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2024-12-23 09:41:36 +00:00
Merge pull request #3895 from haritonch/ocaml-greek-translation
[ocaml/el-gr] Add greek translation for OCaml
This commit is contained in:
commit
9b69738861
381
el-gr/ocaml-gr.html.markdown
Normal file
381
el-gr/ocaml-gr.html.markdown
Normal file
@ -0,0 +1,381 @@
|
||||
---
|
||||
language: OCaml
|
||||
filename: learnocaml-gr.ml
|
||||
contributors:
|
||||
- ["Daniil Baturin", "http://baturin.org/"]
|
||||
translators:
|
||||
- ["Chariton Charitonidis", "https://github.com/haritonch"]
|
||||
---
|
||||
|
||||
Η OCaml είναι μία strictly evaluated συναρτησιακή γλώσσα με κάποια στοιχεία
|
||||
προστακτικού προγραμματισμού.
|
||||
|
||||
Μαζί με την StandardML και τις διαλέκτους της, ανήκει στην οικογένεια ML γλωσσών.
|
||||
Η F# είναι επίσης αρκετά επιρρεασμένη από την OCaml.
|
||||
|
||||
Ακριβώς όπως η StandardML, η OCaml διαθέτει έναν interpreter, που μπορεί να
|
||||
χρησιμοποιηθεί διαδραστικά, αλλά και έναν compiler.
|
||||
Το εκτελέσιμο αρχείο του interpreter κανονικά έχει το όνομα "ocaml" και ο compiler
|
||||
έχει το όνομα "ocamlopt".
|
||||
Υπάρχει και ένας bytecode compiler "ocamlc", αλλά δεν υπάρχουν πολλοί λόγοι να το
|
||||
χρησιμοποιήσει κάποιος.
|
||||
|
||||
Είναι ισχυρά και στατικά τυποποιημένη. Παρ'όλα αυτά , δεν χρειάζεται ο
|
||||
προγραμματιστής να δηλώνει τους τύπους, καθώς συμπερασμός τύπων γίνεται με τον
|
||||
αλγόριθμο του συστήματος τύπων Hindley-Milner. Αυτό κάνει τις δηλώσεις τύπων μη
|
||||
αναγκαίες στις περισσότερες περιπτώσεις, αλλά μπορεί να είναι δύσκολο στην αρχή.
|
||||
|
||||
Όταν είμαστε στο toplevel της OCaml (read-eval-print-loop), η OCaml τυπώνει τον
|
||||
τύπο που συμπεραίνει όταν εισάγουμε μια έκφραση.
|
||||
|
||||
```
|
||||
# let inc x = x + 1 ;;
|
||||
val inc : int -> int = <fun>
|
||||
# let a = 99 ;;
|
||||
val a : int = 99
|
||||
```
|
||||
Για ένα source αρχείο μπορούμε να χρησιμοποιούμε την εντολή
|
||||
"ocamlc -i /path/to/file.ml" στο terminal για να τυπώσει όλα τα ονόματα και
|
||||
τους τύπους.
|
||||
|
||||
```
|
||||
$ cat sigtest.ml
|
||||
let inc x = x + 1
|
||||
let add x y = x + y
|
||||
|
||||
let a = 1
|
||||
|
||||
$ ocamlc -i ./sigtest.ml
|
||||
val inc : int -> int
|
||||
val add : int -> int -> int
|
||||
val a : int
|
||||
```
|
||||
|
||||
Σημειώστε ότι τα type signatures των συναρτήσεων με πολλά ορίσματα είναι
|
||||
γραμμένα σε curried form. Μια συνάρτηση με πολλά ορίσματα μπορεί να
|
||||
αναπαρασταθεί ως σύνθεση συναρτήσεων με μόνο ένα όρισμα.
|
||||
Η "f(x,y) = x + y" από το παράδειγμα, όταν εφαρμόζεται στα ορίσματα 2 και 3
|
||||
είναι ισοδύναμη με την εφαρμογή της "f0(y) = 2 + y" στο 3. Γι' αυτό έχει τύπο
|
||||
"int -> int -> int".
|
||||
|
||||
|
||||
```ocaml
|
||||
(*** Comments ***)
|
||||
|
||||
(* Τα σχόλια περικλείονται σε (* και *). Μπορούν να είναι και εμφωλευμένα *)
|
||||
|
||||
(* Δεν υπάρχει ειδικό σύμβολο για σχόλια μιας γραμμής *)
|
||||
|
||||
|
||||
(*** Μεταβλητές και Συναρτήσεις ***)
|
||||
|
||||
(* Οι εκφράσεις διαχωρίζονται από διπλό semicolon, ";;".
|
||||
Σε πολλές περιπτώσεις είναι περιττό, αλλά εδώ θα το χρησιμοποιούμε σε
|
||||
κάθε έκφραση για ευκολότερο copy-paste στο interpreter shell.
|
||||
Το να χρησιμοποιούμε περιττά ;; σε αρχεία κώδικα θεωρείται συνήθως
|
||||
κακό στυλιστικά. *)
|
||||
|
||||
(* Οι δηλώσεις μεταβλητών και συναρτήσεων χρησιμοποιούν το keyword "let" *)
|
||||
let x = 10 ;;
|
||||
|
||||
(* Η OCaml επιτρέπει χαρακτήρες μονών εισαγωγικών σε identifiers.
|
||||
το μονό εισαγωγικό δεν έχει κάποια σημασία σε αυτή την περίπτωση,
|
||||
χρησιμοποιείται συνήθως σε περιπτώσεις που σε άλλες γλώσσες χρησιμοποιούμε
|
||||
ονόματα όπως "foo_tmp". *)
|
||||
let foo = 1 ;;
|
||||
let foo' = foo * 2 ;;
|
||||
|
||||
(* Από τη στιγμή που ο compiler της OCaml συμπεραίνει τους τύπους αυτόματα,
|
||||
κανονικά δεν χρειάζεται να δηλώνουμε ρητά τον τύπο ορισμάτων. Παρ'όλα αυτά
|
||||
μπορούμε να το κάνουμε αν θέλουμε ή χρειάζεται *)
|
||||
let inc_int (x: int) : int = x + 1 ;;
|
||||
|
||||
(* Μία από αυτές τις περιπτώσεις που είναι αναγκαίο να δηλώσουμε ρητά τύπους
|
||||
είναι για να λύσουμε την αμφισημία μεταξύ δύο record types που έχουν πεδία με
|
||||
όμοια ονόματα. Η εναλλακτική είναι να βάλουμε αυτούς τους τύπους σε modules,
|
||||
αλλά και τα δύο αυτά θέματα είναι εκτός του σκοπού αυτού το μαθήματος. *)
|
||||
|
||||
(* Πρέπει να δηλώνουμε ότι μία συνάρτηση είναι αναδρομική με "rec". *)
|
||||
let rec factorial n =
|
||||
if n = 0 then 1
|
||||
else n * factorial (n-1)
|
||||
;;
|
||||
|
||||
(* H εφαρμογή συναρτήσεων συνήθως δεν χρειάζεται παρενθέσεις γύρω από ορίσματα *)
|
||||
let fact_5 = factorial 5 ;;
|
||||
|
||||
(* ...εκτός αν τα ορίσματα είναι εκφράσεις *)
|
||||
let fact_4 = factorial (5-1) ;;
|
||||
let sqr2 = sqr (-2) ;;
|
||||
|
||||
(* Κάθε συνάρητση πρέπει να έχει τουλάχιστον ένα όρισμα.
|
||||
Από τη στιγμή που κάποιες συναρτήσεις, από τη φύση τους, δεν παίρνουν κάποιο
|
||||
όρισμα, υπάρχει ο τύπος "unit" που έχει μόνο μία τιμή,
|
||||
την οποία γράφουμε ως "()". *)
|
||||
let print_hello () = print_endline "hello world" ;;
|
||||
|
||||
(* Προσέχετε ότι πρέπει να γράφουμε το "()" ως όρισμα και όταν την καλούμε. *)
|
||||
print_hello () ;;
|
||||
|
||||
(* Το να καλούμε μια συνάρτηση με λιγότερα ορίσματα από όσα δέχεται
|
||||
δεν προκαλεί πρόβλημα, απλά παράγει μια νέα συνάρτηση. *)
|
||||
let make_inc x y = x + y ;; (* make_inc is int -> int -> int *)
|
||||
let inc_2 = make_inc 2 ;; (* inc_2 is int -> int *)
|
||||
inc_2 3 ;; (* Αποτιμάται σε 5 *)
|
||||
|
||||
(* Μπορούμε να χρησιμοποιούμε πολλές εκφράσεις στο σώμα μιας συνάρτησης.
|
||||
Η αποτίμηση της τελευταίας έκφρασης είναι η τιμή που επιστρέφει η συνάρτηση.
|
||||
Όλες οι ενδιάμεσες εκφράσεις πρέπει να είναι τύπου "unit".
|
||||
Αυτό είναι ιδιαίτερα χρήσιμο όταν γράφουμε σε προστακτικό στυλ, η απλούστερη
|
||||
μορφή αυτού είναι η εισαγωγή ενός debug print. *)
|
||||
let print_and_return x =
|
||||
print_endline (string_of_int x);
|
||||
x
|
||||
;;
|
||||
|
||||
(* Ως συναρτησιακή γλώσσα η OCaml δεν έχει "procedures" (διαδικασίες).
|
||||
Κάθε συνάρτηση πρέπει να επιστρέφει κάτι. Οπότε, συναρτήσεις που δεν
|
||||
επιστρέφουν κάτι και καλούνται μόνο για τις παρενέργειες τους,
|
||||
όπως η print_endline, επιστρέφουν τιμή τύπου "unit". *)
|
||||
|
||||
|
||||
(* Οι ορισμοί μπορούν να γίνουν αλυσιδωτά με τη δομή "let ... in".
|
||||
Αυτό είναι περίπου το ίδιο με το να αναθέτουμε τιμές σε πολλές μεταβλητές
|
||||
πριν τις χρησιμοποιήσουμε σε εκφράσεις σε προστακτικές γλώσσες. *)
|
||||
let x = 10 in
|
||||
let y = 20 in
|
||||
x + y ;;
|
||||
|
||||
(* Εναλλακτικά μπορούμε να χρησιμποιούμε τη δομή "let ... and ... in".
|
||||
Αυτό είναι εξαιρετικά χρήσιμο για αμοιβαία αποκλειόμενες συναρτήσεις,
|
||||
όπυ με "let .. in", ο compiler θα παραπονιόταν για unbound values *)
|
||||
let rec
|
||||
is_even = function
|
||||
| 0 -> true
|
||||
| n -> is_odd (n-1)
|
||||
and
|
||||
is_odd = function
|
||||
| 0 -> false
|
||||
| n -> is_even (n-1)
|
||||
;;
|
||||
|
||||
(* Οι ανώνυμες συναρτήσεις χρησιμοποιούν την εξής σύνταξη: *)
|
||||
let my_lambda = fun x -> x * x ;;
|
||||
|
||||
(*** Τελεστές ***)
|
||||
|
||||
(* Δεν υπάρχει ιδιαίτερη διάκριση ανάμεσα σε τελεστές και συναρτήσεις.
|
||||
Κάθε τελεστής μπορεί να κληθεί ως συνάρτηση. *)
|
||||
|
||||
(+) 3 4 (* Same as 3 + 4 *)
|
||||
|
||||
(* Υπάρχει ένας αριθμός built-in τελεστών. Ένα ασυνήθιστο χαρακτηριστικό είναι
|
||||
ότι η OCaml δεν μπορεί να κάνει έμμεση μετατροπή τύπων
|
||||
ανάμεσα σε ακεραίους και floats, επίσης, χρησιμοποιεί διαφορετικούς τελεστές
|
||||
για τους floats (αριθμούς κινητής υποδιαστολής) *)
|
||||
12 + 3 ;; (* Πρόσθεση ακεραίων. *)
|
||||
12.0 +. 3.0 ;; (* Πρόσθεση κινητής υποδιαστολής. *)
|
||||
|
||||
12 / 3 ;; (* Διαίρεση ακεραίων. *)
|
||||
12.0 /. 3.0 ;; (* Διαίρεση κινητής υποδιαστολής. *)
|
||||
5 mod 2 ;; (* Υπόλοιπο. *)
|
||||
|
||||
(* Το ενός-ορίσματος μείον είναι αξιοσημείωτη εξαίρεση, είναι πολυμορφικό.
|
||||
Ωστόσο, έχει καθαρές μορφές ακεραίων και float. *)
|
||||
- 3 ;; (* Πολυμορφικό, ακέραιοι *)
|
||||
- 4.5 ;; (* Πολυμορφικό, float *)
|
||||
~- 3 (* Μόνο για integer *)
|
||||
~- 3.4 (* Type error *)
|
||||
~-. 3.4 (* Μόνο για float *)
|
||||
|
||||
(* Μπορούμε να ορίζουμε δικούς μας τελεστές ή να ξανα-ορίσουμε υπάρχοντες.
|
||||
Σε αντίθεση με την SML ή τη Haskell, μόνο ορισμένα σύμβολα μπορούν να
|
||||
χρησιμοποιηθούν για ονόματα τελεστών και το πρώτο σύμβολο ορίζει την
|
||||
επιμεριστικότητα και προτεραιότητα πράξεων. *)
|
||||
let (+) a b = a - b ;; (* και καλή τύχη στον επόμενο... *)
|
||||
|
||||
(* Πιο χρήσιμο: ένας τελεστής αντιστρόφου για floats.
|
||||
οι τελεστές ενός-ορίσματος πρέπει να ξεκινούν με "~". *)
|
||||
let (~/) x = 1.0 /. x ;;
|
||||
~/4.0 (* = 0.25 *)
|
||||
|
||||
|
||||
(*** Built-in δομές δεδομένων ***)
|
||||
|
||||
(* Οι λίστες περικλείονται από αγκύλες και τα στοιχεία τους
|
||||
διαχωρίζονται με semicolons. *)
|
||||
let my_list = [1; 2; 3] ;;
|
||||
|
||||
(* Οι tuples (προαιρετικά) περικλείονται από παρενθέσεις, τα στοιχεία τους
|
||||
διαχωρίζονται με κόμματα. *)
|
||||
let first_tuple = 3, 4 ;; (* Έχει τύπο "int * int". *)
|
||||
let second_tuple = (4, 5) ;;
|
||||
|
||||
(* Συνέπεια: αν προσπαθήσεουμε να διαχωρίσουμε τα στοιχεία μιας λίστας
|
||||
με κόμματα, θα πάρουμε μια λίστα με ένα tuple ως στοιχείο.
|
||||
Μπορεί να την πατήσουμε εύκολα έτσι. *)
|
||||
let bad_list = [1, 2] ;; (* Becomes [(1, 2)] *)
|
||||
|
||||
(* Μπρούμε να προσπελάσουμε στοιχεία μιας λίστας με τη συνάρτηση List.nth. *)
|
||||
List.nth my_list 1 ;;
|
||||
|
||||
(* Yπάρχουν συναρτήσεις ανώτερης τάξης για λίστες, όπως οι map και filter. *)
|
||||
List.map (fun x -> x * 2) [1; 2; 3] ;;
|
||||
List.filter (fun x -> x mod 2 = 0) [1; 2; 3; 4] ;;
|
||||
|
||||
(* Μπορούμε να προσθέτουμε στοιχεία στην αρχή μιας λίστας με τον
|
||||
constructor "::", συνήθως αναφέρεται ως "cons". *)
|
||||
1 :: [2; 3] ;; (* Αποτέλεσμα: [1; 2; 3] *)
|
||||
|
||||
(* Οι πίνακες Arrays περικλείονται από [| |] *)
|
||||
let my_array = [| 1; 2; 3 |] ;;
|
||||
|
||||
(* Προσπελαύνουμε στοιχεία ενός πίνακα ως εξής: *)
|
||||
my_array.(0) ;;
|
||||
|
||||
|
||||
(*** Strings και Χαρακτήρες ***)
|
||||
|
||||
(* Χρησιμοποιούμε διπλά εισαγωγικά για τα string literals. *)
|
||||
let my_str = "Hello world" ;;
|
||||
|
||||
(* Μονά εισαγωγικά για τα literals χαρακτήρων. *)
|
||||
let my_char = 'a' ;;
|
||||
|
||||
(* Τα μονά και τα διπλά εισαγωγικά δεν είναι ισοδύναμα. *)
|
||||
let bad_str = 'syntax error' ;; (* Syntax error. *)
|
||||
|
||||
(* Αυτό μας δίνει ένα string με έναν χαρακτήρα και όχι εναν χαρακτήρα. *)
|
||||
let single_char_str = "w" ;;
|
||||
|
||||
(* Τα strings παρατίθενται με τον τελεστή "^". *)
|
||||
let some_str = "hello" ^ "world" ;;
|
||||
|
||||
(* Τα strings δεν είναι πίνακες από χαρακτήρες όπως στην C.
|
||||
Δεν μπορούμε να ανακατεύουμε strings με χαρακτήρες σε εκφράσεις.
|
||||
Μπορούμε να μετατρέπουμε χαρακτήρες σε strings με "String.make 1 my_char".
|
||||
Υπάρχουν πιο βολικές συναρτήσεις για αυτό το σκοπό σε πρόσθετες βιβλιοθήκες,
|
||||
όπως η Core.Std που μπορεί να μην έχουν εγκατασταθεί/φορτωθεί by default. *)
|
||||
let ocaml = (String.make 1 'O') ^ "Caml" ;;
|
||||
|
||||
(* Υπάρχει και μια συνάρτηση printf. *)
|
||||
Printf.printf "%d %s" 99 "bottles of beer" ;;
|
||||
|
||||
(* Υπάρχουν και συναρτήσεις read/write χωρίς μορφοποίηση. *)
|
||||
print_string "hello world\n" ;;
|
||||
print_endline "hello world" ;;
|
||||
let line = read_line () ;;
|
||||
|
||||
|
||||
(*** User-defined τύποι δεδομένων ***)
|
||||
|
||||
(* Μπορούμε να ορίζουμε τύπους δεδομένων με τη δομή "type some_type".
|
||||
Όπως σε αυτό τον άχρηστο τύπο που αντιγράφει τους ακεραίους: )
|
||||
type my_int = int ;;
|
||||
|
||||
(* Πιο ενδιαφέροντες τύποι περιλαμβάνουν τους λεγόμενους type constructors.
|
||||
Αυτοί πρέπει να ξεκινούν με κεφαλαίο γράμμα. *)
|
||||
type ml = OCaml | StandardML ;;
|
||||
let lang = OCaml ;; (* Έχει τύπο "ml". *)
|
||||
|
||||
(* Οι type constructors δε χρειάζεται να είναι κενοί. *)
|
||||
type my_number = PlusInfinity | MinusInfinity | Real of float ;;
|
||||
let r0 = Real (-3.4) ;; (* Έχει τύπο "my_number". *)
|
||||
|
||||
(* Μπορούν να χρησιμοποιηθούν για πολυμορφική αριθμιτική *)
|
||||
type number = Int of int | Float of float ;;
|
||||
|
||||
(* Σημείο στο επίπεδο, βασικά ένα tuple περιορισμένου συγκεκριμένου τύπου *)
|
||||
type point2d = Point of float * float ;;
|
||||
let my_point = Point (2.0, 3.0) ;;
|
||||
|
||||
(* Οι τύποι μπορούν να είναι παραμετροποιημένοι, όπως σε αυτόν τον τύπο για
|
||||
λίστες λίστών με οτιδήποτε τύπου στοιχεία. Το 'a μπορεί να αντικατασταθεί από
|
||||
οποιονδήποτε τύπο. *)
|
||||
type 'a list_of_lists = 'a list list ;;
|
||||
type int_list_list = int list_of_lists ;;
|
||||
|
||||
(* Οι τύποι μπορούν επίσης να ορίζονται αναδρομικά. Σαν αυτόν εδώ τον τύπο που
|
||||
είναι ανάλογος της built in λίστας από ακεραίους. *)
|
||||
type my_int_list = EmptyList | IntList of int * my_int_list ;;
|
||||
let l = IntList (1, EmptyList) ;;
|
||||
|
||||
|
||||
(*** Ταίριασμα Προτύπων - Pattern Matching ***)
|
||||
|
||||
(* Το ταίριασμα προτύπων είναι κάπως σαν το switch statement σε προστακτικές
|
||||
γλώσσες προγραμματισμού, αλλά παρέχει πολύ μεγαλύτερη εκφραστική ισχύ.
|
||||
|
||||
Παρόλο που φαίνεται περίπλοκο, στην πραγματικότητα είναι απλώς ταίριασμα
|
||||
ενός ορίσματος με μια συγκεκριμένη τιμή, ένα κατηγόρημα ή έναν type constructor
|
||||
Το σύστημα τύπων είναι αυτό που το κάνει τόσο ισχυρό. *)
|
||||
|
||||
(** Ταίριασμα με ακριβείς τιμές. **)
|
||||
|
||||
let is_zero x =
|
||||
match x with
|
||||
| 0 -> true
|
||||
| _ -> false (* Το "_" σημαίνει "οτιδήποτε άλλο". *)
|
||||
;;
|
||||
|
||||
(* Εναλλακτικά μπορούμε να χρησιμοποιούμε το keyword "function". *)
|
||||
let is_one = function
|
||||
| 1 -> true
|
||||
| _ -> false
|
||||
;;
|
||||
|
||||
(* Ταίριασμα με κατηγορήματα, γνωστό και ως "guarded pattern matching". *)
|
||||
let abs x =
|
||||
match x with
|
||||
| x when x < 0 -> -x
|
||||
| _ -> x
|
||||
;;
|
||||
|
||||
abs 5 ;; (* 5 *)
|
||||
abs (-5) ;; (* 5 πάλι *)
|
||||
|
||||
(** Ταίριασμα με type constructors **)
|
||||
|
||||
type animal = Dog of string | Cat of string ;;
|
||||
|
||||
let say x =
|
||||
match x with
|
||||
| Dog x -> x ^ " says woof"
|
||||
| Cat x -> x ^ " says meow"
|
||||
;;
|
||||
|
||||
say (Cat "Fluffy") ;; (* "Fluffy says meow". *)
|
||||
|
||||
(** Διάσχιση δομών δεδομένων με ταίριασμα προτύπων **)
|
||||
|
||||
(* Οι αναδρομικοί τύποι μπορούν να διασχιστούν εύκολα με ταίριασμα προτύπων.
|
||||
Ας δούμε πώς μπορούμε να διασχίσουμε μια λίστα.
|
||||
Παρόλο που το built-in cons ("::") μοιάζει με infix τελεστή,
|
||||
στην πραγματικότητα είναι ένας type constructor και μπορεί να
|
||||
ταιριαστεί όπως όλοι οι type constructors. *)
|
||||
let rec sum_list l =
|
||||
match l with
|
||||
| [] -> 0
|
||||
| head :: tail -> head + (sum_list tail)
|
||||
;;
|
||||
|
||||
sum_list [1; 2; 3] ;; (* Αποτιμάται σε 6 *)
|
||||
|
||||
(* Η built-in συνταξη των cons εμποδίζει τη δομή λίγο, γι αυτό θα φτιάξουμε
|
||||
το δικό μας τύπο λίστας για την παρουσίαση. *)
|
||||
type int_list = Nil | Cons of int * int_list ;;
|
||||
let rec sum_int_list l =
|
||||
match l with
|
||||
| Nil -> 0
|
||||
| Cons (head, tail) -> head + (sum_int_list tail)
|
||||
;;
|
||||
|
||||
let t = Cons (1, Cons (2, Cons (3, Nil))) ;;
|
||||
sum_int_list t ;;
|
||||
|
||||
```
|
||||
|
||||
## Περισσότερα για την OCaml
|
||||
|
||||
* Επισκεφθείτε την επίσημη σελίδα της OCaml για να κατεβάσετε τον compiler και να διαβάσετε το documentation: <http://ocaml.org/>
|
||||
* Δοκιμάστε διαδραστικά μαθήματα και έναν web-based interpreter από την OCaml Pro: <http://try.ocamlpro.com/>
|
Loading…
Reference in New Issue
Block a user