mirror of
https://github.com/adambard/learnxinyminutes-docs.git
synced 2025-07-31 12:00:34 +02:00
added the translations
This commit is contained in:
746
el-gr/racket-gr.html.markdown
Normal file
746
el-gr/racket-gr.html.markdown
Normal file
@@ -0,0 +1,746 @@
|
||||
---σ
|
||||
language: racket
|
||||
filename: learnracket.rkt
|
||||
contributors:
|
||||
- ["th3rac25", "https://github.com/voila"]
|
||||
- ["Eli Barzilay", "https://github.com/elibarzilay"]
|
||||
- ["Gustavo Schmidt", "https://github.com/gustavoschmidt"]
|
||||
- ["Duong H. Nguyen", "https://github.com/cmpitg"]
|
||||
- ["Keyan Zhang", "https://github.com/keyanzhang"]
|
||||
translators:
|
||||
- ["Vasilis Panagiotopoulos" , "https://github.com/billpcs/"]
|
||||
---
|
||||
|
||||
Racket is a general purpose, multi-paradigm programming language in the Lisp/Scheme family.
|
||||
|
||||
Feedback is appreciated! You can reach me at [@th3rac25](http://twitter.com/th3rac25) or th3rac25 [at] [google's email service]
|
||||
|
||||
|
||||
```racket
|
||||
#lang racket ; ορίζει την γλώσσα που χρησιμοποιόυμε
|
||||
|
||||
;;; Σχόλια
|
||||
|
||||
;; Τα σχόλια μιας γραμμής ξεκινούν με ερωτηματικό
|
||||
|
||||
#| Τα σχόλια ολόκληρου μπλόκ
|
||||
μπορούν να εκτείνονται σε πολλές γραμμές και...
|
||||
#|
|
||||
μπορούν να είναι εμφωλευμένα!
|
||||
|#
|
||||
|#
|
||||
|
||||
;; Τα σχόλια S-expression (εκφράσεις S) comments απορρίπτουν την
|
||||
;; έκφραση που ακολουθεί, δυνατότητα που είναι χρήσιμη για να
|
||||
;; κάνουμε σχόλια κάποιες εκφράσεις κατα τη διάρκεια του debugging
|
||||
|
||||
#; (αυτή η έκφραση δεν θα εκτελεστεί)
|
||||
|
||||
;; (Αν δεν καταλαβαίνεται τι είναι οι εκφράσεις , περιμένετε... Θα το μάθουμε
|
||||
;; πολύ συντομα!)
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 1. Πρωτογενείς τύποι μεταβλητών και τελεστές
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; Αριθμοί
|
||||
9999999999999999999999 ; ακέραιοι
|
||||
#b111 ; δυαδικοί => 7
|
||||
#o111 ; οκταδικοί => 73
|
||||
#x111 ; δεκαεξαδικοί => 273
|
||||
3.14 ; πραγματικοί
|
||||
6.02e+23
|
||||
1/2 ; ρητοί
|
||||
1+2i ; μιγαδικοί
|
||||
|
||||
;; Οι μορφή των συναρτήσεων είναι (f x y z)
|
||||
;; όπου το f είναι η συνάρτηση και τα x y z
|
||||
;; είναι οι όροι που η συνάρτηση δέχεται
|
||||
;; ως ορίσματα. Αν θέλουμε να δημιουργήσουμε
|
||||
;; μια λίστα στην κυριολεξία απο δίαφορα δεδομένα,
|
||||
;; χρησιμοποιούμε το ' για να το εμποδίσουμε απο το να
|
||||
;; αξιολογηθεί σαν έκφραση. Για παράδειγμα:
|
||||
'(+ 1 2) ; => Παραμένει (+ 1 2) και δεν γίνεται η πράξη
|
||||
;; Τώρα , ας κάνουμε μερικές πράξεις
|
||||
(+ 1 1) ; => 2
|
||||
(- 8 1) ; => 7
|
||||
(* 10 2) ; => 20
|
||||
(expt 2 3) ; => 8
|
||||
(quotient 5 2) ; => 2
|
||||
(remainder 5 2) ; => 1
|
||||
(/ 35 5) ; => 7
|
||||
(/ 1 3) ; => 1/3
|
||||
(exact->inexact 1/3) ; => 0.3333333333333333
|
||||
(+ 1+2i 2-3i) ; => 3-1i
|
||||
|
||||
;;; Λογικές μεταβλητές
|
||||
#t ; για το true
|
||||
#f ; για το false
|
||||
(not #t) ; => #f
|
||||
(and 0 #f (error "doesn't get here")) ; => #f
|
||||
(or #f 0 (error "doesn't get here")) ; => 0
|
||||
|
||||
;;; Χαρακτήρες
|
||||
#\A ; => #\A
|
||||
#\λ ; => #\λ
|
||||
#\u03BB ; => #\λ
|
||||
|
||||
;;; Τα αλφαριθμητικά είναι πίνακες χαρακτήρων συγκεκριμένου μήκους
|
||||
"Hello, world!"
|
||||
"Benjamin \"Bugsy\" Siegel" ; Το backslash είναι χαρακτήρας διαφυγής
|
||||
"Foo\tbar\41\x21\u0021\a\r\n" ; συμπεριλαμβάνονται οι χαρακτήες διαφυγής της C,
|
||||
; σε Unicode
|
||||
"λx:(μα.α→α).xx" ; μπορούν να υπάρχουν και Unicode χαρακτήρες
|
||||
|
||||
;; Μπορούμε να εννώσουμε αλφαριθμητικά!
|
||||
(string-append "Hello " "world!") ; => "Hello world!"
|
||||
|
||||
;; Ένα αλφαριθμητικό μπορούμε να το χρησιμοπιησουμε
|
||||
;; όπως και μια λίστα απο χαρακτήρες
|
||||
(string-ref "Apple" 0) ; => #\A ;; Παίρνουμε το πρώτο στοιχείο
|
||||
|
||||
;; Η συνάρτηση format μπορεί να χρησιμοποιηθεί για
|
||||
;; να μορφοποιήσουμε αλφαριθμητικά
|
||||
(format "~a can be ~a" "strings" "formatted") ;; => "strings can be formatted"
|
||||
|
||||
;; Η εκτύπωση είναι εύκολη.
|
||||
(printf "I'm Racket. Nice to meet you!\n")
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 2. Μεταβλητές
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; You can create a variable using define
|
||||
;; a variable name can use any character except: ()[]{}",'`;#|\
|
||||
(define some-var 5)
|
||||
some-var ; => 5
|
||||
|
||||
;; You can also use unicode characters
|
||||
(define ⊆ subset?) ;; Εδώ ουστιαστικά δίνουμε στη ήδη ύπαρχουσα συνάρτηση subset?
|
||||
;; ένα νέο όνομα ⊆ , και παρακάτω την καλούμε με το νέο της όνομα.
|
||||
(⊆ (set 3 2) (set 1 2 3)) ; => #t
|
||||
|
||||
;; Αν ζητήσουμε μια μεταβλητή που δεν έχει οριστεί πρίν π.χ
|
||||
(printf name)
|
||||
;; θα πάρουμε το παρακάτω μήνυμα
|
||||
;name: undefined;
|
||||
; cannot reference undefined identifier
|
||||
; context...:
|
||||
|
||||
;; Η τοπική δέσμευση : `me' δευσμεύεται με το "Bob" μόνο μέσα στο (let ...)
|
||||
(let ([me "Bob"])
|
||||
"Alice"
|
||||
me) ; => "Bob"
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 3. Δομές και συλλογές
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Δομές
|
||||
(struct dog (name breed age))
|
||||
(define my-pet
|
||||
(dog "lassie" "collie" 5))
|
||||
my-pet ; => #<dog>
|
||||
(dog? my-pet) ; => #t
|
||||
(dog-name my-pet) ; => "lassie"
|
||||
|
||||
;;; Ζεύγη (αμετάβλητα)
|
||||
;; Η δεσμευμένη λέξη `cons' δημιουργεί ζεύγη,
|
||||
;; και το `car' και το `cdr' εξάγουν το πρώτο και
|
||||
;; το δεύτερο στοιχείο αντίστοιχα.
|
||||
(cons 1 2) ; => '(1 . 2)
|
||||
(car (cons 1 2)) ; => 1
|
||||
(cdr (cons 1 2)) ; => 2
|
||||
|
||||
;;; Λίστες
|
||||
|
||||
;; Οι λίστες είναι linked-list δομές δεδομένων,
|
||||
;; που έχουν δημιουργηθεί απο ζευγάρια 'cons'
|
||||
;; και τελειώνουν με 'null' (ή αλλιώς '()) για να
|
||||
;; δηλώσουν ότι αυτό είναι το τέλος της λίστας
|
||||
(cons 1 (cons 2 (cons 3 null))) ; => '(1 2 3)
|
||||
;; Η δεσμευμένη λέξη 'list' είναι ένας εναλλακτικός
|
||||
;; (και σαφώς πιο βολικός) τρόπος για να δημιουργούμε
|
||||
;; λίστες
|
||||
(list 1 2 3) ; => '(1 2 3)
|
||||
;; αλλά και χρησιμοποιώντας ένα μονό εισαγωγικό το
|
||||
;; το αποτέλεσμα είναι και πάλι το ίδιο
|
||||
'(1 2 3) ; => '(1 2 3)
|
||||
|
||||
;; Μπορούμε και πάλι όμως να χρησιμοποιούμε το 'cons' για να
|
||||
;; προσθέσουμε ένα στοιχείο στην αρχή της λίστας
|
||||
(cons 4 '(1 2 3)) ; => '(4 1 2 3)
|
||||
|
||||
;; Μπορούμε να χρησιμοποιούμε το 'append' για να προσθέτουμε
|
||||
;; στοιχεία στο τέλος μιας λίστας. Το στοιχείο αυτό μπορεί
|
||||
;; και να είναι ολόκληρη λίστα!
|
||||
(append '(1 2) '(3 4)) ; => '(1 2 3 4)
|
||||
|
||||
;; Οι λίστες στην Racket είναι πολύ βασικές , οπότε υπάρχουν πολλές
|
||||
;; δυνατές λειτουργίες για αυτές. Παρακάτω είναι μερικά παραδείγματα:
|
||||
(map add1 '(1 2 3)) ; => '(2 3 4)
|
||||
(map + '(1 2 3) '(10 20 30)) ; => '(11 22 33)
|
||||
(filter even? '(1 2 3 4)) ; => '(2 4)
|
||||
(count even? '(1 2 3 4)) ; => 2
|
||||
(take '(1 2 3 4) 2) ; => '(1 2)
|
||||
(drop '(1 2 3 4) 2) ; => '(3 4)
|
||||
|
||||
;;; Διανύσματα
|
||||
|
||||
;; Τα διανύσματα είναι πίνακες σταθερού μήκους
|
||||
#(1 2 3) ; => '#(1 2 3)
|
||||
|
||||
;; Χρησιμοποιύμε το `vector-append' για να προσθέσουμε διανύσματα
|
||||
(vector-append #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6)
|
||||
|
||||
;;; Σύνολα
|
||||
|
||||
;; Δημιουργούμε ένα σύνολο απο μία λίστα
|
||||
(list->set '(1 2 3 1 2 3 3 2 1 3 2 1)) ; => (set 1 2 3)
|
||||
|
||||
;; Προσθέτουμε έναν αριθμό στο σύνολο χρησιμοποιώντας το `set-add'
|
||||
(set-add (set 1 2 3) 4) ; => (set 1 2 3 4)
|
||||
|
||||
;; Αφαιρούμε με το `set-remove'
|
||||
(set-remove (set 1 2 3) 1) ; => (set 2 3)
|
||||
|
||||
;; Βλέπουμε αν υπάρχει ένας αριθμός στο σύνολο με το `set-member?'
|
||||
(set-member? (set 1 2 3) 1) ; => #t
|
||||
(set-member? (set 1 2 3) 4) ; => #f
|
||||
|
||||
;;; Πίνακες κατακερματισμού
|
||||
|
||||
;; Δημιουργήστε ένα αμετάβλητο πίνακα κατακερματισμού
|
||||
(define m (hash 'a 1 'b 2 'c 3))
|
||||
|
||||
;; Παίρνουμε μια τιμή απο τον πίνακα
|
||||
(hash-ref m 'a) ; => 1
|
||||
|
||||
;; Άν ζητήσουμε μια τιμή που δέν υπάρχει παίρνουμε μία εξαίρεση
|
||||
; (hash-ref m 'd) => no value found for key
|
||||
|
||||
;; Μπορούμε να δώσουμε μια default τιμή για τα κλειδιά που λείπουν
|
||||
(hash-ref m 'd 0) ; => 0
|
||||
|
||||
|
||||
;; Χρησιμοποιούμε το 'hash-set' για να επεκτείνουμε
|
||||
;; ένα πίνακα κατακερματισμού
|
||||
(define m2 (hash-set m 'd 4))
|
||||
m2 ; => '#hash((b . 2) (a . 1) (d . 4) (c . 3))
|
||||
|
||||
;; Θυμηθείτε ! Αυτοί οι πίνακες κατακερματισμού
|
||||
;; είναι αμετάβλητοι!
|
||||
m ; => '#hash((b . 2) (a . 1) (c . 3)) <-- δεν υπάρχει `d'
|
||||
|
||||
;; Χρησιμοποιούμε το `hash-remove' για να αφαιρέσουμε
|
||||
;; κλειδία
|
||||
(hash-remove m 'a) ; => '#hash((b . 2) (c . 3))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 3. Συναρτήσεις
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Χρησιμοποιούμε το `lambda' για να δημιουργήσουμε συναρτήσεις.
|
||||
;; Μια συνάρτηση πάντα επιστρέφει την τιμή της τελευταίας της έκφρασης
|
||||
(lambda () "Hello World") ; => #<procedure>
|
||||
;; Μπορούμε επίσης να χρησιμοποιήσουμε το `λ'
|
||||
(λ () "Hello World") ; => Ίδια συνάρτηση
|
||||
|
||||
;; Χρησιμοποιύμε τις παρενθέσεις για να καλέσουμε όλες τις συναρτήσεις
|
||||
;; συμπεριλαμβανομένων και των εκφράσεων 'λάμδα'
|
||||
((lambda () "Hello World")) ; => "Hello World"
|
||||
((λ () "Hello World")) ; => "Hello World"
|
||||
|
||||
;; Εκχωρούμε σε μια μετάβλητη την συνάρτηση
|
||||
(define hello-world (lambda () "Hello World"))
|
||||
(hello-world) ; => "Hello World"
|
||||
|
||||
;; Μπορούμε αυτό να το κάνουμε συντομότερο χρησιμοποιώντας
|
||||
;; το λεγόμενο syntactic sugar :
|
||||
(define (hello-world2) "Hello World")
|
||||
|
||||
;; Το () στο παραπάνω είναι η λίστα από τα ορίσματα για την συνάρτηση
|
||||
|
||||
(define hello
|
||||
(lambda (name)
|
||||
(string-append "Hello " name)))
|
||||
(hello "Steve") ; => "Hello Steve"
|
||||
;; ... ή ισοδύναμα, χρησιμοποιώντας sugared ορισμό:
|
||||
(define (hello2 name)
|
||||
(string-append "Hello " name))
|
||||
|
||||
;; Μπορούμε να έχουμε συναρτήσεις με πολλές μεταβλητές χρησιμοποιώντας
|
||||
;; το `case-lambda'
|
||||
(define hello3
|
||||
(case-lambda
|
||||
[() "Hello World"]
|
||||
[(name) (string-append "Hello " name)]))
|
||||
(hello3 "Jake") ; => "Hello Jake"
|
||||
(hello3) ; => "Hello World"
|
||||
;; ... ή να ορίσουμε προαιρετικά ορίσματα με μια έκφραση προκαθορισμένης τιμής
|
||||
(define (hello4 [name "World"])
|
||||
(string-append "Hello " name))
|
||||
|
||||
;; Οι συναρτήσεις μπορούν να πακετάρουν επιπλέον
|
||||
;; ορίσματα μέσα σε μια λίστα
|
||||
(define (count-args . args)
|
||||
(format "You passed ~a args: ~a" (length args) args))
|
||||
(count-args 1 2 3) ; => "You passed 3 args: (1 2 3)"
|
||||
;; ... ή με unsugared μορφή `lambda':
|
||||
(define count-args2
|
||||
(lambda args
|
||||
(format "You passed ~a args: ~a" (length args) args)))
|
||||
|
||||
;; Μπορούμε να εμπλέξουμε κανονικά και πακεταρισμένα ορίσματα
|
||||
(define (hello-count name . args)
|
||||
(format "Hello ~a, you passed ~a extra args" name (length args)))
|
||||
(hello-count "Finn" 1 2 3)
|
||||
; => "Hello Finn, you passed 3 extra args"
|
||||
;; ... και unsugared:
|
||||
(define hello-count2
|
||||
(lambda (name . args)
|
||||
(format "Hello ~a, you passed ~a extra args" name (length args))))
|
||||
|
||||
;; Και με λέξεις κλειδία
|
||||
(define (hello-k #:name [name "World"] #:greeting [g "Hello"] . args)
|
||||
(format "~a ~a, ~a extra args" g name (length args)))
|
||||
(hello-k) ; => "Hello World, 0 extra args"
|
||||
(hello-k 1 2 3) ; => "Hello World, 3 extra args"
|
||||
(hello-k #:greeting "Hi") ; => "Hi World, 0 extra args"
|
||||
(hello-k #:name "Finn" #:greeting "Hey") ; => "Hey Finn, 0 extra args"
|
||||
(hello-k 1 2 3 #:greeting "Hi" #:name "Finn" 4 5 6)
|
||||
; => "Hi Finn, 6 extra args"
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 4. Ισότητα
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; για αριθμούς χρησιμοποιούμε το `='
|
||||
(= 3 3.0) ; => #t
|
||||
(= 2 1) ; => #f
|
||||
|
||||
;; Το `eq?' επιστρέφει #t αν δύο 2 ορίσματα αναφέρονται στο
|
||||
;; ίδιο αντικείμενο (στη μνήμη),αλλιώς επιστρέφει #f.
|
||||
;; Με άλλα λόγια, είναι απλή σύγκριση δεικτών.
|
||||
(eq? '() '()) ; => #t, αφού υπάρχει μόνο μια άδεια λίστα στη μνήμη
|
||||
(let ([x '()] [y '()])
|
||||
(eq? x y)) ; => #t, το ίδιο με πάνω
|
||||
|
||||
(eq? (list 3) (list 3)) ; => #f
|
||||
(let ([x (list 3)] [y (list 3)])
|
||||
(eq? x y)) ; => #f — δεν είναι η ίδια λίστα στην μνήμη!
|
||||
|
||||
(let* ([x (list 3)] [y x])
|
||||
(eq? x y)) ; => #t, Αφού το x και το y τώρα δείχνουν στην ίδια θέση
|
||||
|
||||
(eq? 'yes 'yes) ; => #t
|
||||
(eq? 'yes 'no) ; => #f
|
||||
|
||||
(eq? 3 3) ; => #t — να είστε προσεκτικοί εδώ
|
||||
; Είναι προτιμότερο να χρησιμοποιείτε `=' για την
|
||||
; σύγκριση αριθμών.
|
||||
(eq? 3 3.0) ; => #f
|
||||
|
||||
(eq? (expt 2 100) (expt 2 100)) ; => #f
|
||||
(eq? (integer->char 955) (integer->char 955)) ; => #f
|
||||
|
||||
(eq? (string-append "foo" "bar") (string-append "foo" "bar")) ; => #f
|
||||
|
||||
;; Το `eqv?' υποστηρίζει την σύκριση αριθμών αλλα και χαρακτήρων
|
||||
;; Για άλλα ήδη μεταβλητών το `eqv?' και το `eq?' επιστρέφουν το ίδιο.
|
||||
(eqv? 3 3.0) ; => #f
|
||||
(eqv? (expt 2 100) (expt 2 100)) ; => #t
|
||||
(eqv? (integer->char 955) (integer->char 955)) ; => #t
|
||||
|
||||
(eqv? (string-append "foo" "bar") (string-append "foo" "bar")) ; => #f
|
||||
|
||||
;; Το `equal?' υποστηρίζει την σύγκριση των παρακάτω τύπων μεταβλητών:
|
||||
;; `equal?' supports the comparison of the following datatypes:
|
||||
;; αλφαριθμητικά, αλφαριθμητικά από bytes, μεταβλητά ζεύγη , διανύσματα,
|
||||
;; πίνακες κατακερματισμού και δομές.
|
||||
;; Για άλλα ήδη τύπων μεταβλητών το `equal?' και το `eqv?' επιστρέφουν το
|
||||
;; ίδιο αποτέλεσμα.
|
||||
(equal? 3 3.0) ; => #f
|
||||
(equal? (string-append "foo" "bar") (string-append "foo" "bar")) ; => #t
|
||||
(equal? (list 3) (list 3)) ; => #t
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 5. Έλεχγος Ροής
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; Συνθήκες (conditionals)
|
||||
|
||||
(if #t ; έκφραση ελέχγου
|
||||
"this is true" ; έκφραση then
|
||||
"this is false") ; έκφραση else
|
||||
; => "this is true"
|
||||
|
||||
|
||||
;; Στα conditionals, όλες οι μη #f τιμές θεωρούνται ως #t
|
||||
(member 'Groucho '(Harpo Groucho Zeppo)) ; => '(Groucho Zeppo)
|
||||
(if (member 'Groucho '(Harpo Groucho Zeppo))
|
||||
'yep
|
||||
'nope)
|
||||
; => 'yep
|
||||
|
||||
;; Οι αλυσίδες `cond' είναι σειρές από ελέγχους για να
|
||||
;; επιλεγεί ένα αποτέλεσμα
|
||||
(cond [(> 2 2) (error "wrong!")]
|
||||
[(< 2 2) (error "wrong again!")]
|
||||
[else 'ok]) ; => 'ok
|
||||
|
||||
;;; Αντιστοίχιση μοτίβων
|
||||
|
||||
(define (fizzbuzz? n)
|
||||
(match (list (remainder n 3) (remainder n 5))
|
||||
[(list 0 0) 'fizzbuzz]
|
||||
[(list 0 _) 'fizz]
|
||||
[(list _ 0) 'buzz]
|
||||
[_ #f]))
|
||||
|
||||
(fizzbuzz? 15) ; => 'fizzbuzz
|
||||
(fizzbuzz? 37) ; => #f
|
||||
|
||||
;;; Βρόχοι
|
||||
|
||||
;; Οι επαναλήψεις μπορούν να γίνουν μέσω αναδρομής
|
||||
(define (loop i)
|
||||
(when (< i 10)
|
||||
(printf "i=~a\n" i)
|
||||
(loop (add1 i))))
|
||||
(loop 5) ; => i=5, i=6, ...
|
||||
|
||||
;; Παρομοίως με τη χρήση 'let'
|
||||
(let loop ((i 0))
|
||||
(when (< i 10)
|
||||
(printf "i=~a\n" i)
|
||||
(loop (add1 i)))) ; => i=0, i=1, ...
|
||||
|
||||
|
||||
;; Θα δείτε παρακάτω πως να προσθέσουμε μια νέα μορφή επανάληψης
|
||||
;; αλλά η Racket έχει ήδη πολύ ευέλικτη μορφή για τους βρόχους
|
||||
(for ([i 10])
|
||||
(printf "i=~a\n" i)) ; => i=0, i=1, ...
|
||||
(for ([i (in-range 5 10)])
|
||||
(printf "i=~a\n" i)) ; => i=5, i=6, ...
|
||||
|
||||
;;;
|
||||
;;; Επανάληψη μέσα σε ακολουθίες:
|
||||
;; Το `for' επιτρέπει την επενάληψη μέσα σε πολλά
|
||||
;; άλλα ήδη από ακολουθίες: Λίστες, διανύσματα,
|
||||
;; αλφαριθμητικά, σύνολα κτλ..
|
||||
|
||||
;;allows iteration over many other kinds of sequences:
|
||||
;; lists, vectors, strings, sets, hash tables, etc...
|
||||
|
||||
(for ([i (in-list '(l i s t))])
|
||||
(displayln i))
|
||||
|
||||
(for ([i (in-vector #(v e c t o r))])
|
||||
(displayln i))
|
||||
|
||||
(for ([i (in-string "string")])
|
||||
(displayln i))
|
||||
|
||||
(for ([i (in-set (set 'x 'y 'z))])
|
||||
(displayln i))
|
||||
|
||||
(for ([(k v) (in-hash (hash 'a 1 'b 2 'c 3 ))])
|
||||
(printf "key:~a value:~a\n" k v))
|
||||
|
||||
;;; Πιο περίπλοκες επαναλήψεις
|
||||
|
||||
;; Παράλληλη σάρωση σε πολλαπλές ακολουθίες
|
||||
;; (σταματά στην πιο σύντομη)
|
||||
(for ([i 10] [j '(x y z)]) (printf "~a:~a\n" i j))
|
||||
; => 0:x 1:y 2:z
|
||||
|
||||
;; Εμφολευμένοι βρόχοι
|
||||
(for* ([i 2] [j '(x y z)]) (printf "~a:~a\n" i j))
|
||||
; => 0:x, 0:y, 0:z, 1:x, 1:y, 1:z
|
||||
|
||||
;; Συνθήκες
|
||||
(for ([i 1000]
|
||||
#:when (> i 5)
|
||||
#:unless (odd? i)
|
||||
#:break (> i 10))
|
||||
(printf "i=~a\n" i))
|
||||
; => i=6, i=8, i=10
|
||||
|
||||
;;; Σάρωση σε λίστες
|
||||
;; Παρόμοιο με τους βρόχους 'for', απλά συλλέγουμε τα αποτελέσματα
|
||||
|
||||
(for/list ([i '(1 2 3)])
|
||||
(add1 i)) ; => '(2 3 4)
|
||||
|
||||
(for/list ([i '(1 2 3)] #:when (even? i))
|
||||
i) ; => '(2)
|
||||
|
||||
(for/list ([i 10] [j '(x y z)])
|
||||
(list i j)) ; => '((0 x) (1 y) (2 z))
|
||||
|
||||
(for/list ([i 1000] #:when (> i 5) #:unless (odd? i) #:break (> i 10))
|
||||
i) ; => '(6 8 10)
|
||||
|
||||
(for/hash ([i '(1 2 3)])
|
||||
(values i (number->string i)))
|
||||
; => '#hash((1 . "1") (2 . "2") (3 . "3"))
|
||||
|
||||
;; Υπάρχουν πολλά είδη απο προϋπάρχοντες τρόπους για να συλλέγουμε
|
||||
;; τιμές από τους βρόχους
|
||||
(for/sum ([i 10]) (* i i)) ; => 285
|
||||
(for/product ([i (in-range 1 11)]) (* i i)) ; => 13168189440000
|
||||
(for/and ([i 10] [j (in-range 10 20)]) (< i j)) ; => #t
|
||||
(for/or ([i 10] [j (in-range 0 20 2)]) (= i j)) ; => #t
|
||||
;; Και για να χρησιμοποιήσουμε ένα αφθαίρετο συνδιασμό χρησιμοποιύμε
|
||||
;; το 'for/fold'
|
||||
(for/fold ([sum 0]) ([i '(1 2 3 4)]) (+ sum i)) ; => 10
|
||||
;; Αυτό συχνά μπορεί να αντικαταστήσει τους κοινούς
|
||||
;; προστακτικούς βρόχους (imperative loops)
|
||||
|
||||
;;; Εξαιρέσεις
|
||||
|
||||
;; Για να πιάσουμε τις εξαιρέσεις χρησιμοποιούμε το
|
||||
;; `with-handlers'
|
||||
(with-handlers ([exn:fail? (lambda (exn) 999)])
|
||||
(+ 1 "2")) ; => 999
|
||||
(with-handlers ([exn:break? (lambda (exn) "no time")])
|
||||
(sleep 3)
|
||||
"phew") ; => "phew", αλλά αν γίνει το break => "no time"
|
||||
|
||||
;; Χρησιμοποιούμε το 'raise' για να άρουμε μια εξαίρεση
|
||||
;; ή οποιαδήποτε άλλη τιμή
|
||||
(with-handlers ([number? ; πιάνουμε αριθμητικές τιμές
|
||||
identity]) ; και τις επιστρέφουμε σαν απλές τιμές
|
||||
(+ 1 (raise 2))) ; => 2
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 6. Αλλαγή τιμών
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Χρησιμοποιούμε το 'set!' για να θέσουμε μια νέα τιμή
|
||||
;; σε μια ήδη υπάρχουσα μεταβλητή
|
||||
(define n 5)
|
||||
(set! n (add1 n))
|
||||
n ; => 6
|
||||
|
||||
;; Χρησιμοποιούμε τα boxes για να δηλώσουμε ρητά ότι μια μεταβητή
|
||||
;; θα είναι mutable (θα μπορεί να αλλάξη η τιμή της)
|
||||
;; Αυτό είναι παρόμοιο με τους pointers σε άλλες γλώσσες
|
||||
(define n* (box 5))
|
||||
(set-box! n* (add1 (unbox n*)))
|
||||
(unbox n*) ; => 6
|
||||
|
||||
|
||||
;; Πολλοί τύποι μεταβλητών στη Racket είναι αμετάβλητοι πχ τα ζεύγη, οι
|
||||
;; λίστες κτλ. Άλλοι υπάρχουν και σε μεταβλητή και σε αμετάβλητη μορφή
|
||||
;; πχ αλφαριθμητικά, διανύσματα κτλ
|
||||
(define vec (vector 2 2 3 4))
|
||||
(define wall (make-vector 100 'bottle-of-beer))
|
||||
;; Χρησιμοποιούμε το 'vector-set!' για να ανεώσουμε κάποια
|
||||
;; συγκεκριμένη θέση
|
||||
(vector-set! vec 0 1)
|
||||
(vector-set! wall 99 'down)
|
||||
vec ; => #(1 2 3 4)
|
||||
|
||||
|
||||
;; Έτσι δημιουργούμε ένα άδειο μεταβλητό πίνακα κατακερματισμού
|
||||
;; και τον χειριζόμαστε κατάλληλα
|
||||
(define m3 (make-hash))
|
||||
(hash-set! m3 'a 1)
|
||||
(hash-set! m3 'b 2)
|
||||
(hash-set! m3 'c 3)
|
||||
(hash-ref m3 'a) ; => 1
|
||||
(hash-ref m3 'd 0) ; => 0
|
||||
(hash-remove! m3 'a)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 7. Ενότητες (modules)
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;; Οι ενότητες μας επιτρέπουν να οργανώνουμε τον κώδικα σε πολλαπλά
|
||||
;; αρχεία και επαναχρησιμοποιούμενες βιβλιοθήκες
|
||||
;; Εδώ χρησιμοποιούμε υπο-ενότητες, εμφωλευμένες μέσα σε μια
|
||||
;; άλλη ενότητα που δημιουργεί αυτό το κείμενο(ξεκινώντας από
|
||||
;; την γραμμή '#lang' )
|
||||
(module cake racket/base ; ορίζουμε μια ενότητα 'cake' βασισμένο στο
|
||||
; racket/base
|
||||
|
||||
(provide print-cake) ; συνάρτηση που εξάγεται από την ενότητα
|
||||
|
||||
(define (print-cake n)
|
||||
(show " ~a " n #\.)
|
||||
(show " .-~a-. " n #\|)
|
||||
(show " | ~a | " n #\space)
|
||||
(show "---~a---" n #\-))
|
||||
|
||||
(define (show fmt n ch) ; εσωτερική συνάρτηση
|
||||
(printf fmt (make-string n ch))
|
||||
(newline)))
|
||||
|
||||
;; Χρησιμοποιομε το 'require' για να πάρουμε όλα τα
|
||||
;; παρεχόμενα ονόματα από μία ενότητα
|
||||
(require 'cake) ; το ' είναι για τοπική υποενότητα
|
||||
(print-cake 3)
|
||||
; (show "~a" 1 #\A) ; => error, το `show' δεν έχει εξαχθεί
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 8. Κλάσεις και αντικείμενα
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Δημιουργούμε μια κλάση fish% (- συνήθως χρησιμοποιούμε
|
||||
;; το % στο όνομα μιας κλάσης )
|
||||
(define fish%
|
||||
(class object%
|
||||
(init size) ; initialization argument
|
||||
(super-new) ; superclass initialization
|
||||
;; Field
|
||||
(define current-size size)
|
||||
;; Public methods
|
||||
(define/public (get-size)
|
||||
current-size)
|
||||
(define/public (grow amt)
|
||||
(set! current-size (+ amt current-size)))
|
||||
(define/public (eat other-fish)
|
||||
(grow (send other-fish get-size)))))
|
||||
|
||||
;; Δημιουργούμε ένα instance του fish%
|
||||
(define charlie
|
||||
(new fish% [size 10]))
|
||||
|
||||
;; Χρησιμοποιούμε το 'send' για να καλέσουμε
|
||||
;; τις μεθόδους ενός αντικειμένου
|
||||
(send charlie get-size) ; => 10
|
||||
(send charlie grow 6)
|
||||
(send charlie get-size) ; => 16
|
||||
|
||||
;; Το `fish%' είναι μία τιμή "πρώτης κλάσης"
|
||||
;; `fish%' is a plain "first class" value, με το οποίο μπορούμε να
|
||||
;; κάνουμε προσμείξεις
|
||||
(define (add-color c%)
|
||||
(class c%
|
||||
(init color)
|
||||
(super-new)
|
||||
(define my-color color)
|
||||
(define/public (get-color) my-color)))
|
||||
(define colored-fish% (add-color fish%))
|
||||
(define charlie2 (new colored-fish% [size 10] [color 'red]))
|
||||
(send charlie2 get-color)
|
||||
;; ή χωρίς καθόλου ονόματα :
|
||||
(send (new (add-color fish%) [size 10] [color 'red]) get-color)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 9. Μακροεντολές
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Οι μακροεντολές μας επιτρέπουν να επεκτείνουμε
|
||||
;; το συντακτικό μιάς γλώσσας.
|
||||
|
||||
;; Ας προσθέσουμε έναν βρόχο while
|
||||
(define-syntax-rule (while condition body ...)
|
||||
(let loop ()
|
||||
(when condition
|
||||
body ...
|
||||
(loop))))
|
||||
|
||||
(let ([i 0])
|
||||
(while (< i 10)
|
||||
(displayln i)
|
||||
(set! i (add1 i))))
|
||||
|
||||
;; Macros are hygienic, you cannot clobber existing variables!
|
||||
(define-syntax-rule (swap! x y) ; -! is idiomatic for mutation
|
||||
(let ([tmp x])
|
||||
(set! x y)
|
||||
(set! y tmp)))
|
||||
|
||||
(define tmp 2)
|
||||
(define other 3)
|
||||
(swap! tmp other)
|
||||
(printf "tmp = ~a; other = ~a\n" tmp other)
|
||||
;; Η μεταβλητή 'tmp' μετονομάζεται σε 'tmp_1'
|
||||
;; για να αποφευχθεί η σύγκρουση με τα ονόματα
|
||||
;; (let ([tmp_1 tmp])
|
||||
;; (set! tmp other)
|
||||
;; (set! other tmp_1))
|
||||
|
||||
;; But they are still code transformations, for example:
|
||||
(define-syntax-rule (bad-while condition body ...)
|
||||
(when condition
|
||||
body ...
|
||||
(bad-while condition body ...)))
|
||||
;; αυτή η μακροεντολή είναι χαλασένη: δημιουγεί ατέρμονα βρόχο
|
||||
;; και αν προσπαθήσουμε να το χρησιμοποιήσουμε, ο μεταγλωττιστης
|
||||
;; θα μπεί στον ατέρμονα βρόχο.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 10. Συμβόλαια
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Τα συμβόλαια βάζουν περιορισμόυς σε τιμές που προέρχονται
|
||||
;; από ενότητες (modules)
|
||||
(module bank-account racket
|
||||
(provide (contract-out
|
||||
[deposit (-> positive? any)] ; οι ποσότητες είναι πάντα θετικές
|
||||
[balance (-> positive?)]))
|
||||
|
||||
(define amount 0)
|
||||
(define (deposit a) (set! amount (+ amount a)))
|
||||
(define (balance) amount)
|
||||
)
|
||||
|
||||
(require 'bank-account)
|
||||
(deposit 5)
|
||||
|
||||
(balance) ; => 5
|
||||
|
||||
;; Πελάτες που προσπαθούν να καταθέσουν ένα μη θετικό ποσό παίρνουν
|
||||
;; το μήνυμα (deposit -5) ; => deposit: contract violation
|
||||
;; expected: positive?
|
||||
;; given: -5
|
||||
;; more details....
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; 11. Είσοδος και έξοδος
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; Η Racket έχει την έννοια του "port", που είναι παρόμοιο με τα
|
||||
;; file descriptors σε άλλες γλώσσες.
|
||||
|
||||
;; Ανοίγουμε το "/tmp/tmp.txt" και γράφουμε μέσα "Hello World"
|
||||
;; Αυτό θα προκαλούσε σφάλμα αν το αρχείο υπήρχε ήδη
|
||||
(define out-port (open-output-file "/tmp/tmp.txt"))
|
||||
(displayln "Hello World" out-port)
|
||||
(close-output-port out-port)
|
||||
|
||||
;; Προσθέτουμε στο τέλος του "/tmp/tmp.txt"
|
||||
(define out-port (open-output-file "/tmp/tmp.txt"
|
||||
#:exists 'append))
|
||||
(displayln "Hola mundo" out-port)
|
||||
(close-output-port out-port)
|
||||
|
||||
;; Διαβάζουμε απο αρχείο ξανά
|
||||
(define in-port (open-input-file "/tmp/tmp.txt"))
|
||||
(displayln (read-line in-port))
|
||||
; => "Hello World"
|
||||
(displayln (read-line in-port))
|
||||
; => "Hola mundo"
|
||||
(close-input-port in-port)
|
||||
|
||||
;; Εναλλακτικά, με το call-with-output-file δεν χρειάζεται να κλείσουμε
|
||||
;; ρητά το αρχείο
|
||||
(call-with-output-file "/tmp/tmp.txt"
|
||||
#:exists 'update ; Rewrite the content
|
||||
(λ (out-port)
|
||||
(displayln "World Hello!" out-port)))
|
||||
|
||||
;; Και το call-with-input-file κάνει το ίδιο πράγμα για την είσοδο
|
||||
(call-with-input-file "/tmp/tmp.txt"
|
||||
(λ (in-port)
|
||||
(displayln (read-line in-port))))
|
||||
```
|
||||
|
||||
## Επιπλέον πηγές
|
||||
|
||||
Ψάχνεις για περισσότερα ; [Getting Started with Racket](http://docs.racket-lang.org/getting-started/)
|
690
el-gr/scala-gr.html.markdown
Normal file
690
el-gr/scala-gr.html.markdown
Normal file
@@ -0,0 +1,690 @@
|
||||
---
|
||||
language: Scala
|
||||
contributors:
|
||||
- ["George Petrov", "http://github.com/petrovg"]
|
||||
- ["Dominic Bou-Samra", "http://dbousamra.github.com"]
|
||||
- ["Geoff Liu", "http://geoffliu.me"]
|
||||
translators:
|
||||
- ["Vasilis Panagiotopoulos" , "https://github.com/billpcs/"]
|
||||
filename: learnscala-gr.scala
|
||||
lang: el-gr
|
||||
---
|
||||
|
||||
Scala - Η επεκτάσιμη γλώσσα
|
||||
|
||||
```scala
|
||||
|
||||
/*
|
||||
Προετοιμαστείτε:
|
||||
|
||||
1) Κατεβάστε την Scala - http://www.scala-lang.org/downloads
|
||||
2) Κάνετε εξαγωγή στην επιθυμητή σας τοποθεσία και βάλτε τον υποφάκελο bin
|
||||
στο path του συστήματος
|
||||
3) Ξεκινήστε ένα scala REPL γράφοντας scala. Θα πρέπει να βλέπετε το prompt:
|
||||
|
||||
scala>
|
||||
|
||||
Αυτό είναι το αποκαλούμενο REPL (Read-Eval-Print Loop) *.
|
||||
Μπορείτε να πληκτρολογήσετε οποιαδήποτε έγκυρη έκφραση σε Scala μέσα του ,
|
||||
και το αποτέλεσμα θα τυπωθεί. Θα εξηγήσουμε πως μοιάζουν τα αρχεία της Scala
|
||||
αργότερα μέσα στο tutorial , αλλά για τώρα ας αρχίσουμε με κάποια βασικά.
|
||||
*[Βρόχος του Διάβασε - Αξιολόγησε - Τύπωσε]
|
||||
*/
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// 1. Βασικές έννοιες
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
// Τα σχόλια μίας γραμμής ξεκινούν με δύο "/" (:forward slashes) .
|
||||
|
||||
/*
|
||||
Τα σχόλια που επεκτείνονται σε πολλές γραμμές , όπως μπορείτε
|
||||
να δείτε , φαίνοται κάπως έτσι.
|
||||
*/
|
||||
|
||||
// Εκτύπωση με εξαναγκασμό νέας γραμμής στην επόμενη εκτύπωση
|
||||
println("Hello world!")
|
||||
println(10)
|
||||
|
||||
// Εκτύπωση χωρίς τον εξαναγκασμό νέας γραμμής στην επόμενη εκτύπωση
|
||||
print("Hello world")
|
||||
|
||||
// Η δήλωση μεταβλητών γίνεται χρησιμοποιώντας var ή val.
|
||||
// Οι δηλώσεις val είναι αμετάβλητες, ενώ οι var είναι μεταβλητές.
|
||||
// Η αμεταβλητότητα είναι συμφέρουσα και προσπαθούμε να την χρησιμοποιούμε.
|
||||
val x = 10 // το x είναι τώρα 10
|
||||
x = 20 // σφάλμα: αλλαγή σε val
|
||||
var y = 10
|
||||
y = 20 // το y είναι τώρα 20
|
||||
|
||||
/*
|
||||
Η Scala είναι στατικού τύπου γλώσσα, εν τούτις προσέξτε ότι στις παραπάνω
|
||||
δηλώσεις , δεν προσδιορίσαμε κάποιον τύπο. Αυτό συμβαίνει λόγω ενός
|
||||
χαρακτηριστικού της Scala που λέγεται συμπερασματολογία τύπων. Στις
|
||||
περισσότερες των περιπτώσεων , ο μεταγλωττιστής της Scala μπορεί να
|
||||
μαντέψει ποιός είναι ο τύπος μιας μεταβλητής. Μπορούμε να δηλώσουμε
|
||||
αναλυτικά τον τύπο μιάς μεταβλητής ως εξής:
|
||||
*/
|
||||
val z: Int = 10
|
||||
val a: Double = 1.0
|
||||
|
||||
/*
|
||||
Προσέξτε ότι υπάρχει αυτόματη μετατροπή από ακέραιο (Int) σε διπλής
|
||||
ακρίβειας (Double), και συνεπώς το αποτέλεσμα είναι 10.0 και όχι 10.
|
||||
*/
|
||||
val b: Double = 10
|
||||
|
||||
// Λογικές τιμές
|
||||
true
|
||||
false
|
||||
|
||||
// Λογικές Πράξεις
|
||||
!true // false
|
||||
!false // true
|
||||
true == false // false
|
||||
10 > 5 // true
|
||||
|
||||
// Η αριθμιτική είναι όπως τα συνηθισμένα
|
||||
1 + 1 // 2
|
||||
2 - 1 // 1
|
||||
5 * 3 // 15
|
||||
6 / 2 // 3
|
||||
6 / 4 // 1
|
||||
6.0 / 4 // 1.5
|
||||
|
||||
|
||||
/*
|
||||
Αξιολογώντας μια έκφραση στο REPL , σας δίνεται ο τύπος και
|
||||
η τιμή του αποτελέσματος
|
||||
*/
|
||||
|
||||
1 + 7
|
||||
|
||||
/* Η παραπάνω γραμμή έχει το εξής αποτέλεσμα:
|
||||
|
||||
scala> 1 + 7
|
||||
res29: Int = 8
|
||||
|
||||
Αυτό σημαίνει ότι το αποτέλεσμα της αξιολόγησης του 1 + 7 είναι ένα αντικείμενο
|
||||
τύπου Int με τιμή 8
|
||||
|
||||
Σημειώστε ότι το "res29" είναι ένα σειριακά δημιουργούμενο όνομα μεταβλητής
|
||||
για να αποθηκεύονται τα αποτελέσματα των εκφράσεων που έχετε πληκτρολογήσει
|
||||
και συνεπώς η έξοδός σας μπορεί να διαφέρει.
|
||||
*/
|
||||
|
||||
"Τα αλφαριθμητικά στην Scala περικλείονται από διπλά εισαγωγικά"
|
||||
'a' // Ένας χαρακτήρας στην Scala
|
||||
// res30: Char = a
|
||||
// 'Αλφαριθημτικά με μονά εισαγωγικά δεν υφίστανται <= Αυτό θα προκαλέσει σφάλμα.
|
||||
|
||||
// Τα αλφαριθμητικά έχουν τις συνηθισμένες μεθόδους της Java ορισμένες πάνω τους.
|
||||
"hello world".length
|
||||
"hello world".substring(2, 6)
|
||||
"hello world".replace("C", "3")
|
||||
|
||||
// Έχουν επίσης μερικές επιπλένον μεθόδους Scala.
|
||||
// Δείτε επίσης : scala.collection.immutable.StringOps
|
||||
"hello world".take(5)
|
||||
"hello world".drop(5)
|
||||
|
||||
// Παρεμβολή αλφαριθμητικών : παρατηρήστε το πρόθεμα "s"
|
||||
val n = 45
|
||||
s"We have $n apples" // => "We have 45 apples"
|
||||
|
||||
// Expressions inside interpolated strings are also possible
|
||||
// Εκφράσεις μέσα σε παρεμβεβλημένα αλφαριθμητικά είναι επίσης εφικτά
|
||||
val a = Array(11, 9, 6)
|
||||
s"My second daughter is ${a(0) - a(2)} years old." // => "My second daughter is 5 years old."
|
||||
s"We have double the amount of ${n / 2.0} in apples." // => "We have double the amount of 22.5 in apples."
|
||||
s"Power of 2: ${math.pow(2, 2)}" // => "Power of 2: 4"
|
||||
|
||||
// Μορφοποίηση με παρεμβεβλημένα αλφαριθμητικά με το πρόθεμα "f"
|
||||
f"Power of 5: ${math.pow(5, 2)}%1.0f" // "Power of 5: 25"
|
||||
f"Square root of 122: ${math.sqrt(122)}%1.4f" // "Square root of 122: 11.0454"
|
||||
|
||||
// Raw αλφαριθμητικά, που αγνοούν τους ειδικούς χαρακτήρες.
|
||||
raw"New line feed: \n. Carriage return: \r." // => "New line feed: \n. Carriage return: \r."
|
||||
|
||||
// Μερικούς χαρακτήρες πρέπει να τους κάνουμε "escape",
|
||||
// λ.χ ένα διπλό εισαγωγικό μέσα σε ένα αλφαριθμητικό :
|
||||
"They stood outside the \"Rose and Crown\"" // => "They stood outside the "Rose and Crown""
|
||||
|
||||
/*
|
||||
Τα τριπλά διπλά-εισαγωγικά επιτρέπουν στα αλφαριθμητικά να εκτείνονται σε
|
||||
πολλαπλές γραμμές και να περιέχουν διπλά εισαγωγικά
|
||||
*/
|
||||
val html = """<form id="daform">
|
||||
<p>Press belo', Joe</p>
|
||||
<input type="submit">
|
||||
</form>"""
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// 2. Συναρτήσεις
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
// Οι συναρτήσεις ορίζονται ως εξής:
|
||||
//
|
||||
// def functionName(args...): ReturnType = { body... }
|
||||
//
|
||||
// Αν προέρχεστε απο πιο παραδοσιακές γλώσσες (C/C++ , Java) παρατηρήστε
|
||||
// την παράλειψη του return. Στην Scala , η τελευταία έκφραση στο μπλόκ
|
||||
// της συνάρτησης είναι η τιμή που επιστρέφει η συνάρτηση.
|
||||
def sumOfSquares(x: Int, y: Int): Int = {
|
||||
val x2 = x * x
|
||||
val y2 = y * y
|
||||
x2 + y2
|
||||
}
|
||||
|
||||
// Τα { } μπορούν να παραλειφθούν αν η συνάρτηση αποτελείται απο μια απλή έκφραση:
|
||||
def sumOfSquaresShort(x: Int, y: Int): Int = x * x + y * y
|
||||
|
||||
// Η σύνταξη για την κλήση συναρτήσεων είναι γνώριμη:
|
||||
sumOfSquares(3, 4) // => 25
|
||||
|
||||
// Στις περισσότερες των περιπτώσεων (με τις αναδρομικές συναρτήσεις να αποτελούν
|
||||
// την πιο αξιοπρόσεκτη εξαίρεση) , ο τύπος επιστροφής της συνάρτησης μπορεί να
|
||||
// παραλειφθεί, και η ίδια συμπερασματολογία τύπων που είδαμε με τις μεταβλητές
|
||||
// θα δουλεύει και με τους τύπους επιστροφής της συνάρτησης:
|
||||
def sq(x: Int) = x * x // Ο μεταγλωττιστής μπορεί να μαντέψει ότι
|
||||
// ο τύπος επιστροφής της συνάρτησης είναι Int
|
||||
|
||||
// Οι συναρτήσεις μπορούν να έχουν προκαθορισμένες τιμές:
|
||||
def addWithDefault(x: Int, y: Int = 5) = x + y
|
||||
addWithDefault(1, 2) // => 3
|
||||
addWithDefault(1) // => 6
|
||||
|
||||
|
||||
// Οι ανώνυμες συναρτήσεις είναι ως εξής:
|
||||
(x:Int) => x * x
|
||||
|
||||
// Σε αντίθεση με τα defs , ακόμα και ο τύπος εισόδου απο τις ανώνυμες
|
||||
// συναρτήσεις μπορεί να παραληφθεί αν τα συμφραζόμενα το κάνουν ξεκάθαρο.
|
||||
// Προσέξτε τον τύπο "Int => Int" που σημαίνει ότι μια συνάρτηση παίρνει
|
||||
// ένα Int και επιστρέφει ένα Int.
|
||||
val sq: Int => Int = x => x * x
|
||||
|
||||
// Οι ανώνυμες συναρτήσεις μπορούν να κληθούν όπως συνήθως:
|
||||
sq(10) // => 100
|
||||
|
||||
// Αν κάθε όρισμα στην ανώνυμη συνάρτηση χρησιμοποιείται μόνο μία φορά,
|
||||
// η Scala επιτρέπει έναν ακόμα πιο σύντομο τρόπο να οριστεί. Αυτές
|
||||
// οι ανώνυμες συναρτήσεις αποδεικνύεται ότι είναι πολύ κοινές ,
|
||||
// όπως θα γίνει προφανές στο μέρος των δομών δεδομένων.
|
||||
val addOne: Int => Int = _ + 1
|
||||
val weirdSum: (Int, Int) => Int = (_ * 2 + _ * 3)
|
||||
|
||||
addOne(5) // => 6
|
||||
weirdSum(2, 4) // => 16
|
||||
|
||||
// Η δεσμευμένη λέξη return υπάρχει στην Scala , αλλά επιστρέφει μόνο
|
||||
// από το πιο εσωτερικό def που την περικλείει.
|
||||
// ΠΡΟΣΟΧΗ: Η χρήση του return στην Scala είναι επιρρεπής σε λάθη
|
||||
// και θα πρέπει να αποφεύγεται.
|
||||
// Δεν έχει καμία επίδραση στις ανώνυμες συναρτήσεις. Για παράδειγμα:
|
||||
def foo(x: Int): Int = {
|
||||
val anonFunc: Int => Int = { z =>
|
||||
if (z > 5)
|
||||
return z // Αυτή η σειρά κάνει το z την τιμή που επιστρέφει η foo!
|
||||
else
|
||||
z + 2 // Αυτή η γραμμή είναι η τιμή που επιστρέφει η anonFunc
|
||||
}
|
||||
anonFunc(x) // Αυτή η γραμμή είναι η τιμή που επιστρέφει η foo
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// 3. Έλεγχος ροής
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
1 to 5
|
||||
val r = 1 to 5
|
||||
r.foreach( println )
|
||||
|
||||
r foreach println
|
||||
// ΠΡΟΣΟΧΗ: Η Scala είναι σχετικά επιεικής ως αναφορά τις τελείες και
|
||||
// τις παρενθέσεις. Διαβάστε τους κανόνες ξεχωριστά.
|
||||
// Αυτό βοηθάει στο να γράφεις DSLs και APIs που διαβάζονται σαν τα Αγγλικά.
|
||||
|
||||
(5 to 1 by -1) foreach ( println )
|
||||
|
||||
// Ένας βρόχος while :
|
||||
var i = 0
|
||||
while (i < 10) { println("i " + i); i+=1 }
|
||||
|
||||
while (i < 10) { println("i " + i); i+=1 } // Ναι ξανά! Τι συνέβει; Γιατί;
|
||||
|
||||
i // Εμφάνισε την τιμή του i. Σημειώστε ότι ένας βρόχος while είναι βρόχος
|
||||
// με την κλασική έννοια - εκτελείται σειριακά καθώς αλλάζει η μεταβλητή
|
||||
// του βρόχου. Το while είναι πολύ γρήγορο , γρηγορότερο απο τους βρόχους
|
||||
// της Java , αλλά η χρήση combinators και comprehensions όπως πιο πάνω ,
|
||||
// είναι πιο εύκολη στην κατανόηση και στην παραλληλοποίηση.
|
||||
|
||||
// Ένας βρόχος do while :
|
||||
do {
|
||||
println("x is still less than 10");
|
||||
x += 1
|
||||
} while (x < 10)
|
||||
|
||||
// Η αναδρομή ουράς είναι ένας ιδιωματικός τρόπος να κάνεις επαναλαμβανόμενα
|
||||
// πράγματα στην Scala. Οι αναδρομικές συναρτήσεις απαιτούν να γράφτεί
|
||||
// ρητά τον τύπο που θα επιστρέψουν , αλλιώς ο μεταγλωττιστής δεν μπορεί
|
||||
// αλλιώς να τον συνάγει. Παρακάτω είναι μια συνάρτηση που επιστρέφει Unit.
|
||||
def showNumbersInRange(a:Int, b:Int):Unit = {
|
||||
print(a)
|
||||
if (a < b)
|
||||
showNumbersInRange(a + 1, b)
|
||||
}
|
||||
showNumbersInRange(1,14)
|
||||
|
||||
|
||||
// Η ροή του ελέγχου.
|
||||
|
||||
val x = 10
|
||||
|
||||
if (x == 1) println("yeah")
|
||||
if (x == 10) println("yeah")
|
||||
if (x == 11) println("yeah")
|
||||
if (x == 11) println ("yeah") else println("nay")
|
||||
|
||||
println(if (x == 10) "yeah" else "nope")
|
||||
val text = if (x == 10) "yeah" else "nope"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// 4. Δομές Δεδομένων
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
val a = Array(1, 2, 3, 5, 8, 13)
|
||||
a(0)
|
||||
a(3)
|
||||
a(21) // "Πετάει" exception
|
||||
|
||||
val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo")
|
||||
m("fork")
|
||||
m("spoon")
|
||||
m("bottle") // "Πετάει" exception
|
||||
|
||||
val safeM = m.withDefaultValue("no lo se")
|
||||
safeM("bottle")
|
||||
|
||||
val s = Set(1, 3, 7)
|
||||
s(0)
|
||||
s(1)
|
||||
|
||||
/* Δείτε το documentation του map εδώ -
|
||||
* http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Map
|
||||
*/
|
||||
|
||||
|
||||
// Πλειάδες
|
||||
|
||||
(1, 2)
|
||||
|
||||
(4, 3, 2)
|
||||
|
||||
(1, 2, "three")
|
||||
|
||||
(a, 2, "three")
|
||||
|
||||
// Γιατί να το έχουμε αυτό;
|
||||
val divideInts = (x:Int, y:Int) => (x / y, x % y)
|
||||
|
||||
divideInts(10,3) // Η συνάρτηση divideInts επιστρέφει το αποτέλεσμα
|
||||
// της ακαίρεας διαίρεσης και το υπόλοιπο.
|
||||
|
||||
// Για να έχουμε πρόσβαση στα στοιχεία μιας πλειάδας, χρησιμοποιούμε το _._n
|
||||
// όπου το n είναι ο δείκτης με βάση το 1 του στοιχείου.
|
||||
val d = divideInts(10,3)
|
||||
|
||||
d._1
|
||||
|
||||
d._2
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// 5. Αντικειμενοστραφής Προγραμματισμός
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
Ότι έχουμε κάνει ως τώρα σε αυτό το tutorial ήταν απλές εκφράσεις
|
||||
(τιμές , συναρτήσεις , κτλ). Αυτές οι εκφράσεις βολεύουν όταν τις
|
||||
γράφουμε στο REPL για γρήγορες δοκιμές, αλλά δεν μπορούν να υπάρχουν
|
||||
από μόνες τους σε ένα αρχείο Scala. Για παράδειγμα , δεν μπορούμε να
|
||||
έχουμε μόνο ένα "val x = 5" στο αρχείο Scala. Αντί αυτού , τα μόνα
|
||||
στοιχεία του πάνω επιπέδου που επιτρέπονται στην Scala είναι:
|
||||
|
||||
- αντικείμενα (objects)
|
||||
- κλάσεις (classes)
|
||||
- κλάσεις περίπτωσης (case classes στην Scala)
|
||||
- Χαρακτηριστικά (traits , όπως ονομάζονται στην Scala)
|
||||
|
||||
Και τώρα θα εξηγήσουμε τι είναι αυτά.
|
||||
*/
|
||||
// Οι κλάσεις είναι παρόμοιες με τις κλάσεις σε άλλες γλώσσες. Τα ορίσματα του
|
||||
// "κατασκευαστή" (constructor) δηλώνονται μετά από το όνομα της κλάσης ,
|
||||
// και η αρχικοποιήση γίνεται μέσα στο σώμα της κλάσης.
|
||||
class Dog(br: String) {
|
||||
// Κώδικας για τον "κατασκευαστή"
|
||||
var breed: String = br
|
||||
|
||||
// Ορίζεται μια μέθοδος bark , που επιστρέφει ένα αλφαριθμητικό
|
||||
def bark = "Woof, woof!"
|
||||
|
||||
// Οι τιμές και οι μέθοδοι είναι public εκτός αν χρησιμοποιήσουμε κάποια
|
||||
// απο τις λέξεις κλειδιά "protected" και "private" .
|
||||
private def sleep(hours: Int) =
|
||||
println(s"I'm sleeping for $hours hours")
|
||||
|
||||
// Οι abstract μέθοδοι είναι απλά μέθοδοι χωρίς σώμα. Αν βγάζαμε
|
||||
// το σχόλιο απο την επόμενη γραμμή η κλάση Dog θα έπρεπε να
|
||||
// δηλωθεί ως abstract class Dog(...) { ... } :
|
||||
// def chaseAfter(what: String): String
|
||||
}
|
||||
|
||||
val mydog = new Dog("greyhound")
|
||||
println(mydog.breed) // => "greyhound"
|
||||
println(mydog.bark) // => "Woof, woof!"
|
||||
|
||||
|
||||
// Η λέξη "object" δημιουργεί ένα type ΚΑΙ ένα singleton instance αυτού.
|
||||
// Είναι κοινό για τις κλάσεις στην Scala να έχουν ένα "συντροφικό object",
|
||||
// όπου η συμπεριφορά για κάθε instance αιχμαλωτίζεται μέσα στις κλάσεις
|
||||
// αυτές καθ' αυτές, αλλά η συμπρεριφορά που σχετίζεται με όλα τα instances
|
||||
// της κλάσης πάνε μέσα στο object. Η διαφορά είναι παρόμοια με τις
|
||||
// μεθόδους κλάσεων σε σχέση με στατικές μεθόδους σε άλλες γλώσσες.
|
||||
// Προσέξτε οτι τα objects και οι κλάσεις μπορούν να έχουν το ίδιο όνομα.
|
||||
object Dog {
|
||||
def allKnownBreeds = List("pitbull", "shepherd", "retriever")
|
||||
def createDog(breed: String) = new Dog(breed)
|
||||
}
|
||||
|
||||
// Οι κλάσεις περίπτωσης (case classes) είναι που έχουν την επιπλέον
|
||||
// λειτουργικότητα ενσωματωμένη. Μιά συνήθης ερώτηση για αρχάριους στην
|
||||
// Scala είναι πότε να χρησιμοπούνται κλάσεις και πότε case κλάσεις.
|
||||
// Γενικά οι κλάσεις τείνουν να εστιάζουν στην ενθυλάκωση, τον
|
||||
// πολυμορφισμό και τη συμπεριφορά. Οι τιμές μέσα σε αυτές τις κλάσεις
|
||||
// τείνουν να είναι private , και μόνο οι μέθοδοι είναι εκτεθειμένες.
|
||||
// Ο κύριος σκοπός των case classes είναι να κρατούν δεδομένα που είναι
|
||||
// σταθερές(immutable). Συνήθως έχουν λίγες μεθόδους και οι μέθοδοι σπάνια
|
||||
// έχουν παρενέργειες.
|
||||
case class Person(name: String, phoneNumber: String)
|
||||
|
||||
// Δημιουργία ενός instance. Πραρατηρήστε ότι τα case classes
|
||||
// δεν χρειάζονται την λέξη "new" .
|
||||
val george = Person("George", "1234")
|
||||
val kate = Person("Kate", "4567")
|
||||
|
||||
// Με τα case classes, παίρνεις μερικά προνόμια δωρεάν , όπως:
|
||||
george.phoneNumber // => "1234"
|
||||
|
||||
// Ελέχγεται η ισότητα για κάθε πεδίο (δεν χρειάζεται να
|
||||
// κάνουμε override στο .equals)
|
||||
Person("George", "1234") == Person("Kate", "1236") // => false
|
||||
|
||||
// Έυκολος τρόπος να κάνουμε αντιγραφή. Δημιουργούμε έναν νέο geroge:
|
||||
// otherGeorge == Person("george", "9876")
|
||||
val otherGeorge = george.copy(phoneNumber = "9876")
|
||||
|
||||
// Και πολλά άλλα. Τα case classes έχουν και αντιστοίχιση προτύπων
|
||||
// (pattern matching) δωρεάν, δείτε παρακάτω.
|
||||
|
||||
// Τα χαρακτηριστικά (traits) έρχονται σε λίγο καιρό !
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// 6. Αντιστοίχιση Προτύπων
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
// Η αντιστοίχιση προτύπων (pattern matching) είναι ένα πολύ δυνατό και
|
||||
// ευρέως χρησιμοποιούμενο χαρακτηριστικό στην Scala. Παρακάτω βλέπουμε
|
||||
// πως γίνεται το pattern matching σε ένα case class. Σημείωση: Σε
|
||||
// αντίθεση με άλλες γλώσσες η Scala δεν χρειάζεται breaks, γιατί γίνεται
|
||||
// αυτόματα όταν γίνει κάποιο match.
|
||||
|
||||
def matchPerson(person: Person): String = person match {
|
||||
// Μετά προσδιορίζουμε το πρότυπο (pattern):
|
||||
case Person("George", number) => "We found George! His number is " + number
|
||||
case Person("Kate", number) => "We found Kate! Her number is " + number
|
||||
case Person(name, number) => "We matched someone : " + name + ", phone : " + number
|
||||
}
|
||||
|
||||
val email = "(.*)@(.*)".r // Ορίζουμε ένα regex για το επόμενο παράδειγμα.
|
||||
// (regex <- REGular EXpression)
|
||||
|
||||
// Το pattern matching μπορεί να μοιάζει γνώριμο απο τα switch statements σε
|
||||
// γλώσσες που ανήκουν στην οικογένεια της C αλλά είναι πολύ πιο ισχυρό.
|
||||
// Στην Scala , μπορούμε να κάνουμε match πολύ περισσότερα:
|
||||
def matchEverything(obj: Any): String = obj match {
|
||||
// Μπορούμε να ταιριάξουμε τιμές:
|
||||
case "Hello world" => "Got the string Hello world"
|
||||
|
||||
// Μπορούμε να ταιριάξουμε τύπους:
|
||||
case x: Double => "Got a Double: " + x
|
||||
|
||||
// Μπορούμε να βάλουμε συνθήκες:
|
||||
case x: Int if x > 10000 => "Got a pretty big number!"
|
||||
|
||||
// Μπορούμε να ταιριάξουμε case classes όπως πρίν:
|
||||
case Person(name, number) => s"Got contact info for $name!"
|
||||
|
||||
// Μπορούμε να ταιριάξουμε regex:
|
||||
case email(name, domain) => s"Got email address $name@$domain"
|
||||
|
||||
// Μπορούμε να ταιριάξουμε πλειάδες:
|
||||
case (a: Int, b: Double, c: String) => s"Got a tuple: $a, $b, $c"
|
||||
|
||||
// Μπορούμε να ταιριάξουμε δομές δεδομένων:
|
||||
case List(1, b, c) => s"Got a list with three elements and starts with 1: 1, $b, $c"
|
||||
|
||||
// Μπορούμε να ταιριάξουμε πρότυπα που το ένα είναι μέσα στο άλλο:
|
||||
case List(List((1, 2,"YAY"))) => "Got a list of list of tuple"
|
||||
}
|
||||
|
||||
// Στην πραγματικότητα , μπορούμε να κάνουμε pattern matching σε όποιο αντικείμενο
|
||||
// έχει την μέθοδο "unapply". Αυτό το χαρακτηριστικό είναι τόσο ισχυρό ώστε
|
||||
// η Scala επιτρέπει να ορίστούν ολόκληρες συναρτήσεις σαν patterns.
|
||||
val patternFunc: Person => String = {
|
||||
case Person("George", number) => s"George's number: $number"
|
||||
case Person(name, number) => s"Random person's number: $number"
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// 7. Συναρτησιακός Προγραμματισμός
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
// Η Scala επιτρέπει στις μεθόδους και τις συναρτήσεις να επιστρέφουν ή να
|
||||
// δέχονται ως παραμέτρους άλλες μεθόδους ή συναρτήσεις.
|
||||
|
||||
val add10: Int => Int = _ + 10 // Μια συνάρτηση που δέχεται Int και επιστρέφει Int
|
||||
List(1, 2, 3) map add10 // List(11, 12, 13) - το add10 εφαρμόζεται σε κάθε στοιχείο
|
||||
// μέσω του map
|
||||
|
||||
// Οι ανώνυμες συναρτήσεις μπορούν να χρησιμοποιηθούν αντί
|
||||
// ονοματισμένων (όπως απο πάνω) :
|
||||
List(1, 2, 3) map (x => x + 10)
|
||||
|
||||
// Και το σύμβολο της κάτω παύλας , μπορεί να χρησιμοποιηθεί αν υπάρχει μόνο
|
||||
// ένα όρισμα στην ανώνυμη συνάρτηση. Έτσι δεσμεύεται ως η μεταβλητή.
|
||||
List(1, 2, 3) map (_ + 10)
|
||||
|
||||
// Αν το μπλόκ της ανώνυμης συνάρτησης ΚΑΙ η συνάρτηση που εφαρμόζεται
|
||||
// (στην περίπτωσή μας το foreach και το println) παίρνουν ένα όρισμα
|
||||
// μπορείτε να παραλείψετε την κάτω παύλα.
|
||||
List("Dom", "Bob", "Natalia") foreach println
|
||||
|
||||
|
||||
// Συνδυαστές
|
||||
|
||||
s.map(sq)
|
||||
|
||||
val sSquared = s. map(sq)
|
||||
|
||||
sSquared.filter(_ < 10)
|
||||
|
||||
sSquared.reduce (_+_)
|
||||
|
||||
// Η συνάρτηση filter παίρνει ένα κατηγορούμενο (predicate)
|
||||
// που είναι μια συνάρτηση απο το A -> Boolean και διαλέγει
|
||||
// όλα τα στοιχεία που ικανοποιούν αυτό το κατηγορούμενο.
|
||||
List(1, 2, 3) filter (_ > 2) // List(3)
|
||||
case class Person(name:String, age:Int)
|
||||
List(
|
||||
Person(name = "Dom", age = 23),
|
||||
Person(name = "Bob", age = 30)
|
||||
).filter(_.age > 25) // List(Person("Bob", 30))
|
||||
|
||||
|
||||
// Το foreach είναι μια μέθοδος της Scala , που ορίζεται για ορισμένες
|
||||
// συλλογές (collections). Παίρνει έναν τύπο και επιστρέφει Unit
|
||||
// (μια μέθοδο void)
|
||||
val aListOfNumbers = List(1, 2, 3, 4, 10, 20, 100)
|
||||
aListOfNumbers foreach (x => println(x))
|
||||
aListOfNumbers foreach println
|
||||
|
||||
// For comprehensions
|
||||
|
||||
for { n <- s } yield sq(n)
|
||||
|
||||
val nSquared2 = for { n <- s } yield sq(n)
|
||||
|
||||
for { n <- nSquared2 if n < 10 } yield n
|
||||
|
||||
for { n <- s; nSquared = n * n if nSquared < 10} yield nSquared
|
||||
|
||||
/*
|
||||
Προσοχή : Αυτά δεν ήταν βρόχοι for. Η σημασιολογία ενός βρόχου for είναι
|
||||
η επανάληψη, ενώ ένα for-comprehension ορίζει μια σχέση μεταξύ δύο
|
||||
συνόλων δεδομένων.
|
||||
*/
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// 8. Implicits
|
||||
/////////////////////////////////////////////////
|
||||
/*
|
||||
ΠΡΟΣΟΧΗ! Τα implicits είναι ένα σύνολο απο ισχυρά χαρακτηριστικά της Scala
|
||||
και επομένως είναι εύκολο να γίνει κατάχρηση. Οι αρχάριοι στην Scala θα
|
||||
πρέπει να αντισταθούν στον πειρασμό να τα χρησιμοποιήσουν έως ότου, όχι
|
||||
μόνο καταλάβουν πως λειτουργούν, αλλά ακόμα εξασκηθούν πάνω τους.
|
||||
Ο μόνος λόγος που συμπεριλάβαμε αυτό το κομμάτι στο tutorial είναι
|
||||
γιατί είναι τόσο κοινό στις βιβλιοθήκες της Scala , που αδύνατο να κάνεις
|
||||
οτιδήποτε σημαντικό χωρίς να χρησιμοποιήσεις μια που να έχει implicits.
|
||||
|
||||
*/
|
||||
|
||||
// Κάθε τιμή (vals , συναρτήσεις , αντικείμενα , κτλ) μπορεί να δηλωθεί ως
|
||||
// implicit χρησιμοποιώντας , ναι το μαντέψατε , την λέξη "implicit".
|
||||
// Σημειώστε ότι χρησιμοποιούμε την κλάση Dog που δημιουργήσαμε στο
|
||||
// 5ο μέρος των παραδειγμάτων.
|
||||
implicit val myImplicitInt = 100
|
||||
implicit def myImplicitFunction(breed: String) = new Dog("Golden " + breed)
|
||||
|
||||
|
||||
// Απο μόνη της, η λέξη implicit, δεν αλλάζει την συμπεριφορά μιάς τιμής
|
||||
// οπότε οι παραπάνω μπορούν να χρησιμοποιοηθούν όπως συνήθως.
|
||||
myImplicitInt + 2 // => 102
|
||||
myImplicitFunction("Pitbull").breed // => "Golden Pitbull"
|
||||
|
||||
// Η διαφορά είναι ότι τώρα αυτές οι τιμές έχουν την δυνατότητα να
|
||||
// χρησιμοποιηθούν όταν ένα άλλο κομμάτι κώδικα "χρειάζεται" μια
|
||||
// implicit τιμή. Μια τέτοια περίπτωση είναι τα ορίσματα μιας implicit
|
||||
// συνάρτησης:
|
||||
def sendGreetings(toWhom: String)(implicit howMany: Int) =
|
||||
s"Hello $toWhom, $howMany blessings to you and yours!"
|
||||
|
||||
// Άν τροφοδοτήσουμε μια τιμή για το "homMany", η συνάρτηση συμπεριφέρεται
|
||||
// ως συνήθως
|
||||
sendGreetings("John")(1000) // => "Hello John, 1000 blessings to you and yours!"
|
||||
|
||||
// Αλλά αν παραλείψουμε την παράμετρο implicit , μια implicit τιμή του ιδίου τύπου
|
||||
// χρησιμοποιείται, στην περίπτωσή μας, το "myImplicitInt"
|
||||
sendGreetings("Jane") // => "Hello Jane, 100 blessings to you and yours!"
|
||||
|
||||
// Οι παράμετροι implicit συναρτήσεων μας επιτρέπουν να προσομοιάζουμε
|
||||
// κλάσεις τύπων (type classes) σε άλλες συναρτησιακές γλώσσες.
|
||||
// Χρησιμοποιείται τόσο συχνά που έχει την δικιά του συντομογραφία.
|
||||
// Οι επόμενες δύο γραμμές κώδικα σημαίνουν το ίδιο πράγμα.
|
||||
def foo[T](implicit c: C[T]) = ...
|
||||
def foo[T : C] = ...
|
||||
|
||||
|
||||
|
||||
// Μια άλλη περίπτωση στην οποία ο μεταγλωττιστής αναζητά μια implicit τιμή
|
||||
// είναι αν έχετε obj.method (...)
|
||||
// αλλά το "obj" δεν έχει την "method" ως μέθοδο. Σε αυτή την περίπτωση,
|
||||
// αν υπάρχει μια implicit μετατροπή του τύπου Α => Β, όπου Α είναι ο τύπος
|
||||
// του obj, ενώ το Β έχει μία μέθοδο που ονομάζεται «method», εφαρμόζεται η
|
||||
// εν λόγω μετατροπή. Έτσι, έχοντας την MyImplicitFunction μέσα στο πεδίο
|
||||
// εφαρμογής(scope), μπορούμε να πούμε:
|
||||
"Retriever".breed // => "Golden Retriever"
|
||||
"Sheperd".bark // => "Woof, woof!"
|
||||
|
||||
// Εδώ το String αρχικά μετατρέπεται σε Dog χρησιμοποιώντας την συνάρτησή μας
|
||||
// παραπάνω, και μετά καλείται η κατάλληλη μέθοδος. Αυτό είναι ένα εξερετικά
|
||||
// ισχυρό χαρακτηριστικό, αλλά δεν πρέπει να χρησιμοποιείται με ελαφριά την
|
||||
// καρδιά. Μάλιστα, όταν ορίσατε την συνάρτηση implicit παραπάνω, ο μεταγλωττιστής
|
||||
// θα πρέπει να σας έδωσε μια προειδοποιήση, ότι δεν πρέπει να το κάνετε αυτό
|
||||
// εκτός αν πραγματικά γνωρίζετε τι κάνετε.
|
||||
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// 9. Διάφορα
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
// Εισαγωγή βιβλιοθηκών κτλ
|
||||
import scala.collection.immutable.List
|
||||
|
||||
// Εισαγωγή των πάντων απο το scala.collection.immutable
|
||||
import scala.collection.immutable._
|
||||
|
||||
// Εισαγωγή πολλών κλάσεων σε μία έκφραση
|
||||
import scala.collection.immutable.{List, Map}
|
||||
|
||||
// Δώστε ένα νέο όνομα στην εισαγωγή σας χρησιμοποιώντας το '=>'
|
||||
import scala.collection.immutable.{ List => ImmutableList }
|
||||
|
||||
// Εισαγωγή όλων των κλάσεων εκτός απο μερικές.
|
||||
// Το επόμενο δεν εισάγει το Map και το Set:
|
||||
import scala.collection.immutable.{Map => _, Set => _, _}
|
||||
|
||||
// Το σημείο εισαγωγής του προγράμματος σας ορίζεται σε ένα αρχείο scala ,
|
||||
// χρησιμοποιώντας ένα αντικείμενο (object), με μία μέθοδο , την main.
|
||||
object Application {
|
||||
def main(args: Array[String]): Unit = {
|
||||
// Εδω γράφουμε ...
|
||||
}
|
||||
}
|
||||
|
||||
// Files can contain multiple classes and objects. Compile with scalac
|
||||
// Τα files μπορούν να περιέχουν περισσότερες απο μία κλάσεις και
|
||||
// αντικείμενα. Το compile γίνεται με την εντολή scalac
|
||||
|
||||
// Εισαγωγή και εξαγωγή.
|
||||
|
||||
// Για να διβάσετε ένα αρχείο γραμμή προς γραμμή
|
||||
import scala.io.Source
|
||||
for(line <- Source.fromFile("myfile.txt").getLines())
|
||||
println(line)
|
||||
|
||||
// Για να γράψετε σε ένα αρχείο
|
||||
val writer = new PrintWriter("myfile.txt")
|
||||
writer.write("Writing line for line" + util.Properties.lineSeparator)
|
||||
writer.write("Another line here" + util.Properties.lineSeparator)
|
||||
writer.close()
|
||||
|
||||
```
|
||||
|
||||
## Further resources
|
||||
|
||||
[Scala for the impatient](http://horstmann.com/scala/)
|
||||
|
||||
[Twitter Scala school](http://twitter.github.io/scala_school/)
|
||||
|
||||
[The scala documentation](http://docs.scala-lang.org/)
|
||||
|
||||
[Try Scala in your browser](http://scalatutorials.com/tour/)
|
||||
|
||||
Join the [Scala user group](https://groups.google.com/forum/#!forum/scala-user)
|
||||
|
Reference in New Issue
Block a user