Τρίτη 23 Φεβρουαρίου 2016

Εγχειρίδιο της Μ2000 - Τεύχος 15ο

7. Τιμές και Παράμετροι (δυο διαφορετικές έννοιες).

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

7.1. Περί τιμών

Η Μ2000 χρησιμοποιεί τιμές που γράφουμε στο κώδικα όπως 1234 ή "Γράμματα" με τρεις τρόπους:

  • Απόδοση Ονόματος σε Τιμή
  • Πέρασμα τιμής ως Παράμετρο
  • Άμεση Χρήση  

7.1.1 Τιμές

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

Εδώ θα δούμε μερικές ειδικές περιπτώσεις τιμών.
Οι συνηθισμένες τιμές είναι οι Αριθμοί και τα Γράμματα.
Π.χ  το 1024 είναι αριθμός και το "Γιώργος" αλλά και το "1024" είναι γράμματα γιατί έχουν δυο σύμβολα ένα αρχής και ένα τέλους που λένε "ότι βλέπεις είναι απλά σειρές χαρακτήρων".

Για τα Αλφαριθμητικά, τα  σύμβολα αρχής και τέλους μπορεί να είναι τα διπλά εισαγωγικά ή οι αγκύλες (οι αγκύλες χρησιμοποιούνται και για μπλοκ εντολών, αλλά ο διερμηνευτής τις ξεχωρίζει και για αλφαριθμητικά). Στις αγκύλες μπορούμε να συμπεριλάβουμε κείμενο:
α$= { Αυτή είναι η πρώτη παράγραφος
            αυτή η δεύτερη
            αυτή η τρίτη
            }
Η θέση της αγκύλης στο τέλος καθορίζει πόσα διαστήματα θα αφαιρεθούν από την δεύτερη και μετά παράγραφο. Έτσι όλο το κείμενο μπορούμε να το μεταφέρουμε δεξιά με το Tab στον ενσωματωμένο διορθωτή κάνοντας το κώδικα ευανάγνωστο.

Για τους αριθμούς έχουμε αρκετές μορφές:

  • Ακέραιος: 100  -300 +50650  
  • Δεκαδικός 10.2342     .2442 (χωρίς μηδέν μπροστά) (βάζουμε πρόσημα αν θέλουμε)
  • Επιστημονική μορφή 1.23432e-54 1.23432ε-54 (το e δουλεύει και με το ελληνικό ε)
                                    Α=1.223222ε-45
                                    Τύπωσε Α

  • Δεκαεξαδική μορφή
                                    Α%= 0xFFFFFFFF
                                    Τύπωσε Α% ' 4294967295
                                    Δεκαεξ Α%
                                    Β%= 0xFFFFFFFF&
                                    Τύπωσε Β%=-1

Σε παλαιότερες εκδόσεις οι μεταβλητές με % χρησίμευαν για ακέραιες τιμές, ενώ εσωτερικά ήταν τύπου Double. Κατά την απόδοση τιμής τα δεκαδικά απορρίπτονται με το μαθητικό στρογγύλεμα (στο 0.5). Στις νεότερες εκδόσεις, ισχύει το στρογγύλεμα, αλλά ο τύπος μεταβλητής μπορεί να είναι οποιοσδήποτε από το σύνολο τύπων που χρησιμοποιεί η Μ2000. Όπως double, single, currency, decimal, long, integer (boolean αλλά δεν βγάζει καλά αποτελέσματα).  Στο παράδειγμα μια Τύπωσε Τύπος$(Β%) θα δώσει Long (32bit ακέραιος με πρόσημο). Το 
Τύπος$(Α%) θα δώσει Currency. Στις μεταβλητές εντός τμημάτων/συναρτήσεων ο τύπος δίνεται μια φορά και μετά δεν αλλάζει. Στη κονσόλα, στη γραμμή εντολών (που δημιουργούμε γενικές) μπορούμε να αλλάξουμε τύπο (έχει παραμείνει όπως στις παλιές εκδόσεις), εκτός του τύπου Long (αυτός ο τύπος υποστηριζόταν από τις αρχικές εκδόσεις).
  • Χρώμα κατά Html με χρήση του # στην αρχή ενός εξαψήφιου δεκαεξαδικού.
                        Πένα 0x80000012 : Τύπωσε "Χρώμα"    \\ εδικά χρώματα των Windows
                        Πένα #33AADD : Τύπωσε "Χρώμα"  \\ RGB χρώματα
                        Α=#33AADD \\ we can use it like a number – return a negative number
                        Πένα 14 \\ 0 .. 15 τα βασικά των windows
                        Τύπωσε Δεκαεξ$(Α,3)
                        Α=Χρώμα(100,200,30) \\ RGB με τιμές στο δεκαδικό νούμερο

  • Ημερομηνία-Ώρα (δίνονται μέσω συναρτήσεων)
                  Μ=Σήμερα : Χ=Τώρα
                  Τύπωσε Γραφή$(Χ,"hh:mm:ss")
                  Τύπωσε Γραφή$(Μ,"yyyy/mm/dd")
                  Χ1= Υπωρα(Χ,3,30) \\ +3 ώρες και 30 λεπτά
                  Τύπωσε Γραφή$(Χ1,"hh:mm:ss")
                  Μ1=Υπμερ(Μ,0,100) \\100 μήνες από τώρα!
                  Τύπωσε Γραφή$(Μ1,"yyyy/mm/dd")
                  Τύπωσε Ημέρα$(Μ1) \\ κανονική έξοδος
                  Τύπωσε Χρόνος$(Χρόνος("10:20")) \\κανονική έξοδος σε ώρες και λεπτά μόνο!
                  \\ μπορούμε να δώσουμε το μμ γιατί έχουμε ελληνικά σαν γλώσσα.
                  Τύπωσε Κωδ("Γ")=195 ' αν δεν δώσει αληθές δεν έχουμε ελληνικά ως κύρια γλώσσα!
                  Αν Κωδ("Γ")=195 τότε {
                        Χ=Ημέρα("31/12/2000")+Χρόνος("10:30μμ") \\βάζουμε μια ημέρα & ώρα στο Χ
                  } Αλλιώς {
                        Χ=Ημέρα(γραφη$("2000 12, 31", "yyyy/mm/dd"))+Χρόνος("22:30")
                  }
                  Τύπωσε Γραφή$(Χ,"Long Date") \\ πάντα στα Ελληνικά!
                  Τύπωσε Ημέρα$(Χ)
                  Τύπωσε Χρόνος$(Χ) \\ δίνει 22:30
                  Τοπικό 1033
                  Τύπωσε Τοπικό$(55+10) ' October 1033
                  Τοπικό 1049
                  \\ Οκτώβριος επειδή η εφαρμογή έχει εξ ορισμού Ελληνικό Locale Id.
                  Τύπωσε Γραφή$(Ημέρα("2010/10/12"), "mmmm")
                  Τύπωσε Τοπικό$(55+Τιμή(Γραφή$(Ημέρα("2010/10/12"),"m") )) ' Октябрь 1049 Ρώσικα
                  

Η εντολή Greek ή Ελληνικά γυρνάει το τοπικό στο 1032 (και τα μηνύματα σφαλμάτων στα ελληνικά), όπως και η Τοπικό 1032 (αλλά χωρίς την αλλαγή των μηνυμάτων). Για το 1033 η εντολή Latin ή Λατινικά γυρνάει το τοπικό στο 1033 (και τα μηνύματα σφαλμάτων στα αγγλικά). Όταν έχουμε 1032, τότε οι Boolean εμφανίζονται ως Αληθές/Ψευδές, ενώ ότι άλλο True/False.
  • Μακρύς (Long) 32bit ακέραιος 
            Μακρύς Α=-1 \\μπορεί να είναι αρνητικός!
            \\ Μετατροπή τα bits του μακρύ σε δυαδικό χωρίς πρόσημο
            Τύπωσε Δεκαεξ$(Δυαδικό.Ακέραιο(Α),4) \\ FFFFFFFF
            \\ Μετατροπή δυαδικού (unsign) σε ακέραιο 32bit (sign)
            Α=Ακέραιο.Δυαδικό(0χFF00AA00)
            Τύπωσε 0χFF00AA00, Δυαδικό.Ακέραιο(Α)
            Δεκαεξ 0χFF00AA00, Δυαδικό.Ακέραιο(Α)
            Τύπωσε Α


Η Ακέραιο.Δυαδικό() στις νέες εκδόσεις γυρνάει Currency.  Επειδή η Α είναι Long θα πάρει την τιμή με μετατροπή αυτόματα. Αν προσπαθήσουμε να δώσουμε τιμή εκτός ορίων θα βγει λάθος υπερχείλισης (overflow).

 7.1.2 Περί Αριθμού/Τύπων Παραμέτρων 

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

Κάνε άλφα(χ)=2*χ*2-5*χ+10
Τύπωσε άλφα(10)


Η εντολή Κάνε απλά φτιάχνει το παρακάτω σε μια γραμμή, παίρνει τις παραμέτρους που έχουμε στην παρένθεση και τις βάζει σε μια διάβασε.

Συνάρτηση άλφα {
      Διάβασε χ
      =2*χ*2-5*χ+10
}
Τύπωσε άλφα(10)

Ας δούμε με ένα απλό παράδειγμα τι κάνει ο διερμηνευτής:

Αν έχουμε κλήση συνάρτησης και περνάμε μια τιμή έστω 1234 τότε ο διερμηνευτής ετοιμάζει ένα αντικείμενο εκτέλεσης με το κώδικα της συνάρτησης, του αποδίδει έναν νέο σωρό τιμών και σε αυτόν βάζει το 1234  (αν είχαμε παράσταση θα έβαζε την τιμή που θα έβρισκε) και μετά ξεκινάει αυτό το αντικείμενο εκτέλεσης!
Η Μ2000 δεν αποτιμά την έκφραση όταν την παραδίδει σε μια παράμετρο, ούτε όταν η παράμετρος χρησιμοποιηθεί, αλλά πιο πριν, δηλαδή πρώτα αποτιμά όλες τις παραμέτρους και σώνει τις τιμές σε ένα σωρό που δίνεται στο αντικείμενο εκτέλεσής της και μετά είναι θέμα της συνάρτησης αν θα πάρει και πότε τις τιμές, Ό,τι δεν πάρει θα χαθεί μαζί με αυτόν τον σωρό. Στην συνάρτηση σε μια γραμμή (με την Κάνε) έχουμε άμεση απόδοση των τιμών στις παραμέτρους, επειδή δεν μπορούμε να βάλουμε κώδικα για να επέμβουμε στο σωρό.
Σε όλες τις περιπτώσεις που χρησιμοποιούμε μια συνάρτηση σε πολλές γραμμές με την Συνάρτηση { } μπορούμε να σκεφτούμε πώς θα "δράσουμε" στην επεξεργασία της εισαγωγής τιμών, πόσες και ποιες παραμέτρους χρειαζόμαστε, αν κάποια πρέπει να προηγηθεί για να προετοιμάσει το χώρο για να τακτοποιηθούν οι άλλες. Υπάρχει τρόπος για οκνηρή αποτίμηση με μεταφορά σε παράμετρο συνάρτηση που όταν θα χρησιμοποιηθεί, τότε θα αποτιμηθεί η παράσταση (έχω δώσει παραδείγματα με την Οκν$() από την λέξη Οκνηρή) και εδώ θα δούμε και άλλα.

Έχουμε δει την εντολή Ταύτιση() όπου  ένα Τάυτιση("ΓΑ") θα δώσει -1 (Αληθές) αν στην κορυφή του σωρού είναι αλφαριθμητικό (Γράμματα) και αμέσως μετά είναι αριθμός.
Επιπλέον μπορούμε να χρησιμοποιήσουμε τιμή από το σωρό για μια φορά χωρίς να την περάσουμε σε μεταβλητή (οι αριθμός και γράμμα$ κάνουν ακριβώς αυτό)

Τρέχουμε το m2000.exe και γράφουμε Σ Α(  και έτσι ανοίγει ο διορθωτής για να γράψουμε συνάρτηση (και έτσι η συνάρτηση γίνεται άμεσα γενική)

Αν ταύτιση("ΑΑ") τότε {
      =Αριθμός>Αριθμός
} Αλλιώς.ΑΝ ταύτιση("ΓΓ") τότε {
      =Γράμμα$>Γράμμα$
}

Δείτε λοιπόν ότι μπορούμε να δώσουμε αυτές τις δυο εντολές

Τύπωσε Α("Αλφα","Βήτα"), Α(1,2)

Δηλαδή καλέσαμε την Α() με δυο διαφορετικές ταυτότητες παραμέτρων,  δίνοντας από την μεριά της κλήσης τιμές και από την μεριά του κώδικα της συνάρτησης (που τρέχει κάθε φορά σε άλλο αντικείμενο εκτέλεσης) ελέγχουμε την ύπαρξη μιας "ταυτότητας" τιμών, και ανάλογα δίνουμε αποτέλεσμα. Σε άλλες γλώσσες αν θέλει κανείς να φτιάξει διαφορετικές Α() βάσει παραμέτρων γράφει ξεχωριστές και ο μεταφραστής βρίσκει από το τι παραμέτρους βάζουμε ποια από τις διαφορετικές Α() χρησιμοποιούμε. Εδώ έχουμε μια συνάρτηση αλλά με δυνατότητα να ελέγχει τι πήρε σε τύπους πριν καν τους αποδώσει σε μεταβλητές. Μια συνάρτηση μπορεί να έχει τμήματα, και επειδή τα τμήματα δέχονται το σωρό του πατρικού, μπορεί η συνάρτηση απλά να δει τι παραμέτρους έχει και να καλέσει ένα τμήμα αφήνοντας τον σωρό ως έχει. Τα τμήματα επιστρέφουν σε σωρό τιμές, ή μπορεί η συνάρτησή μας να δώσει μια μεταβλητή με αναφορά για το αποτέλεσμα. Έτσι παρέχοντας τον σωρό τιμών  και την μεταβλητή για επιστροφή έχουμε τμήματα που με ευκολία προγραμματιστικά θα βάλουμε.

Δυο ακόμα παρατηρήσεις: Μία είναι ότι δεν χρησιμοποιούμε εδώ μεταβλητές που με μια Διάβασε θα έπαιρναν τιμές και μια δεύτερη είναι ότι η επιστροφή τιμής είναι προκαθορισμένη να είναι αριθμητική ή αριθμητικός πίνακας ή αντικείμενο (δεν μπορούμε να το ξέρουμε αυτό αν δεν δούμε το κώδικα, και μπορεί να έχουμε και τα τρία αν θέλουμε, ανάλογα με την είσοδο).
Ας δούμε τον κώδικα με μεταβλητές και να μη γράψουμε τη συνάρτηση απ΄ευθείας στην λίστα τμημάτων/συναρτήσεων "επιπέδου 0",  δηλαδή να ανήκουν σε άλλη συνάρτηση ή άλλο τμήμα:

Συνάρτηση Α {
      Αν ταύτιση("ΑΑ") τότε {
            Διάβασε Α, Β
            =Α>Β
      } Αλλιώς.ΑΝ ταύτιση("ΓΓ") τότε {
            Διάβασε Α$, Β$
            =Α$>Β$
      }
}
Τύπωσε Α("Αλφα","Βήτα"), Α(1,2)

Με την χρήση των Αριθμός και Γράμμα$ "σηκώνουμε" άμεσα τιμές από το σωρό αλλά δεν τις καταχωρούμε. Μπορούμε βέβαια να βγάλουμε αντίγραφα με την εντολή Πάνω.

Άδειασε  ' Αδειάζουμε το σωρό για το παράδειγμα
Σειρά 10, 20 ' χρήση FIFO
\\ μπορούμε να αφαιρέσουμε την επόμενη γραμμή - δεν αλλάζει κάτι στη Τύπωσε
Σειρά 100, 200 ' πάνε στο τέλος του σωρού, το 200 ως τελευταίο στοιχείο
Πάνω 2 : Πάνω 2
Διάβασε Α1, Β1, Α2, Β2
Τύπωσε Α1, Β1, Α2, Β2


Η εντολή Πάνω 2 παίρνει το 20 και το φέρνει στην κορυφή άρα ο σωρός έχει το 20,10,20,100,200
Μετά μια όμοια εντολή παίρνει το 2ο που είναι το 10 και το περνάει "Πάνω" από τη κορυφή και το κάνει κορυφή 10,20,10,20,100,200
Η εντολή Πάνω αντιγράφει οτιδήποτε στοιχείο, πίνακες και αντικείμενα (που μπορούν να έχουν οτιδήποτε, άλλους πίνακες και άλλα αντικείμενα).

Πίνακας Α(20)=10
Βάλε Α()
Πάνω \\ τον διπλασιάζω
Α(3)=100
Διάβασε Γ(),Δ()
Τύπωσε Γ(3), Δ(3) ' 10    100
Α(3)=5000
Τύπωσε Γ(3), Δ(3) ' 10    100


Γιατί συμβαίνει το Γ(3) να έχει 10 και το Δ(3) να έχει 100; Διότι το Βάλε Α() έβαλε ουσιαστικά αναφορά στον Α() ενώ η Πάνω έφτιαξε νέο πίνακα και έβαλε μια νέα σειρά τιμών. Αλλάζοντας το Α(3) σε 100 δεν άλλαξε στο αντίγραφο. Όταν διαβάζω την Γ() τότε διαβάζω το αντίγραφο.
“η Διάβασε διαβάζει πάντα από την κορυφή του σωρού, η Βάλε βάζει πάντα στην κορυφή του σωρού, η Σειρά βάζει πάντα στο τέλος του σωρού.”
Όταν διαβάσω την Δ() τότε βγαίνει ένα αντίγραφο (όπως κάνει η Πάνω) αλλά για την Δ() μόνο. Η απόδειξη είναι στις επόμενες γραμμές. Αλλάζω την Α(3) σε 5000 και η Δ() δεν αλλάζει πια.
Γιατί γίνεται αυτό; Για να αποφεύγεται η διπλή αντιγραφή, μία με την Βάλε και μια με την Διάβασε. Με την Πάνω όμως κάνουμε στην ουσία διπλή αντιγραφή, αλλά αυτό θέλουμε!

Στη κλήση όμως μιας συνάρτησης ο σωρός είναι νέος, άρα δεν θα βρούμε εκεί κάτι που να είχε περάσει σε χρόνο πριν την κλήση. Άρα ουσιαστικά δεν μπορώ να δώσω μια Α(3)=100 πριν την κλήση συνάρτησης και εφόσον περάσω στο σωρό της τον πίνακα!  Αυτά γίνονται μόνο στα τμήματα που θα δούμε αργότερα! Μπορούμε όπου θέλουμε να βάζουμε μια εντολή Σωρός για να μας δείχνει τον τρέχοντα σωρό ή αν θέλουμε ξεκινάμε το πρόγραμμα με τη φόρμα της δοκιμής (γράψτε δοκιμή ή δοκιμή και το όνομα του τμήματος για να ανοίξει η φόρμα). Για την φόρμα αυτή θα δούμε σε επόμενο τεύχος.
Δείτε κάτι που κάνουν οι νεότερες εκδόσεις. Δίνουμε στην Αλφα() μια σειρά τιμών, ως παραμέτρους (Variadic λέγονται οι συναρτήσεις που παίρνουν μεταβλητό αριθμό τιμών). Το [] επιστρέφει το σωρό τιμών, ενώ αφήνει ως τρέχον ένα κενό σωρό. Το Κ παίρνει το δείκτη στο αντικείμενο mStiva (που είναι ο Μ2000 σωρός τιμών). Μπορούμε να δούμε κάποια τιμή χωρίς να την αφαιρέσουμε με την ΤιμήΣωρού() και ΤιμήΣωρού$() για αλφαριθμητικά. Μπορούμε να συνδέσουμε το σωρό ως τρέχον με την Σωρός Κ { } και όταν βγούμε από την δομή γυρνάει ο τρέχον όπως ήταν (δεν μπορούμε να πειράξουμε τον παλιό στη δομή Σωρός, η Μ2000 δεν δίνει δείκτη στον τρέχον σωρό, οι εντολές, οι συναρτήσεις και οι μεταβλητές μόνο για ανάγνωση όπως η ΚΕΝΟ βρίσκουν τον δείκτη από το αντικείμενο εκτέλεσης). Ο μόνος τρόπος να πάρουμε δείκτη, είναι να βγάλουμε το σωρό με την [],  αποδίδοντας ένα νέο ως τρέχον.
Συνάρτηση Αλφα() {
      =[]
}

Κ=Αλφα(1,2,30,4,5)
Τύπωσε Τύπος$(Κ)="mStiva"
Τύπωσε ΤιμήΣωρού(Κ, 3)=30
Σωρός Κ {
      Ενώ όχι Κενό: Τύπωσε Αριθμός: Τέλος Ενώ
}

Μπορούμε έναν σωρό να τον αδειάσουμε βάζοντας τα στοιχεία του στο τέλος του τρέχοντα σωρού:
Άδειασε
Βάλε "οκ"
κ=Σωρός:=1,2,3,"Λέξη", 5
Τύπωσε Μήκος(κ)=5
Σωρός κ
Τύπωσε Μήκος(κ)=0
Ενώ όχι Κενό {
      Αν ΕινΑρ Τότε Τύπωσε Αριθμός Αλλιώς Τύπωσε Γράμμα$
}

7.1.2.1 Προαιρετικές Παράμετροι

Από την 8η έκδοση έχουμε προαιρετικές παραμέτρους:

Συνάρτηση Αλφα {
\\ αρχικές τιμές
      Χ=10
      Υ=5
\\ αν δεν υπάρχει τιμή αφήνει την αρχική
      Διάβασε ? Χ, Υ
      = Χ*Υ
}
Τύπωσε Αλφα() ' 50
Τύπωσε Αλφα(2) ' 10
Τύπωσε Αλφα(,2) ' 20
Τύπωσε Αλφα(2,3) ' 6


Θα μπορούσαμε να έχουμε δυο Διάβασε και η δεύτερη ή η πρώτη να ήταν προαιρετική (με το ?). Δηλαδή δεν μας υποχρεώνει κάτι να χρησιμοποιήσουμε με μια Διάβασε το πέρασμα παραμέτρων, και ούτε όλα να είναι προαιρετικά όπως στο παράδειγμα.

Παράδειγμα της τρέχουσας έκδοσης (11, αναθεώρηση 11)
Συνάρτηση Τυπ$(κ) {
      =Τύπος$(κ)
}
Συνάρτηση Αλφα(Χ=10, Υ=5) {
      = Χ*Υ
}
Τύπωσε Αλφα() ' 50
Τύπωσε Αλφα(2) ' 10
Τύπωσε Αλφα(,2) ' 20
Τύπωσε Αλφα(2,3) ' 6
Τύπωσε Τυπ$(Αλφα(2,3))="Double"
Τύπωσε Τυπ$(Αλφα(2@,3@))="Decimal"
Τύπωσε Τυπ$(Αλφα(2&,3&))="Long"
// Αναπρογραμματίζουμε την Αλφα(), αυτό γίνεται στη Μ2000
Συνάρτηση Αλφα(Χ ως Απλός=10, Υ ως Απλός=5) {
      = Χ*Υ
}
Τύπωσε Τυπ$(Αλφα(2,3))="Single"
Τύπωσε Τυπ$(Αλφα(2@,3@))="Single"
Τύπωσε Τυπ$(Αλφα(2&,3&))="Single"

Με Απλές Συναρτήσεις
Συνάρτηση Τυπ$(κ) {
      =Τύπος$(κ)
}
Αδειασε
Βάλε 100, 300
Τύπωσε @Αλφα() ' 30000
Τύπωσε @Αλφα(2) ' 10
Τύπωσε @Αλφα(,2) ' 20
Τύπωσε @Αλφα(2,3) ' 6
Τύπωσε Τυπ$(@Αλφα(2,3))="Double"
Τύπωσε Τυπ$(@Αλφα(2@,3@))="Decimal"
Τύπωσε Τυπ$(@Αλφα(2&,3&))="Long"


Συνάρτηση Αλφα(Χ=10, Υ=5)

      = Χ*Υ

Τέλος Συνάρτησης

1. Οι απλές συναρτήσεις δεν αλλάζουν κώδικα κατά την εκτέλεση. Επίσης βλέπουν τις μεταβλητές/συναρτήσεις/τμήματα/ρουτίνες του τμήματος. Δημιουργούμε νέες μεταβλητές/πίνακες με την Τοπική/Τοπικές.
2. Οι απλές συναρτήσεις μπορούν να έχουν προαιρετικές μεταβλητές αλλά απαιτούν καλό χειρισμό γιατί διαφέρουν από τις κανονικές (και τις λάμδα), ο σωρός τιμών στις απλές είναι ίδιος με αυτός του τμήματος από όπου κλήθηκε. Δείτε ότι βάλαμε δυο τιμές και τις πήρε η πρώτη Τύπωσε @Αλφα() ' 30000. Αν θέλουμε να μην έχουμε θέμα, τότε βάζουμε το  ? στη θέση της τιμής:
Τύπωσε @Αλφα(?, ?) ' 50

 Αν δεν αποδοθεί τιμή σε μεταβλητή η Μ2000 βγάζει λάθος (δεν αφήνει παραμέτρους χωρίς τιμή)

7.1.3 Πολλαπλή Εισαγωγή Τιμών και Εξαγωγή Στοιχείων

Αυτό που επιστρέφει μια συνάρτηση λέγεται στοιχείο, και αυτό το στοιχείο μπορεί να είναι η τιμή για μια παράμετρο σε μια άλλη συνάρτηση. Τα στοιχεία αν δεν περνάνε σε άλλες συναρτήσεις/τμήματα/ρουτίνες τότε αποθηκεύονται προσωρινά ή στο δίσκο σε αρχεία.
Για τα τμήματα αυτή είναι η πιο εύκολη υπόθεση επειδή δέχονται έναν σωρό κάνουν αλλαγές, επεξεργασία και σε αυτόν κάνουν επιστροφές (χώρια σε παραμέτρους που έχουμε περάσει με αναφορά). Ο συναρτήσεις κανονικά γυρνάνε μια τιμή, του τύπου που ορίζει το όνομά τους π.χ. Α() γυρνάει αριθμό, το Α%() γυρνάει ακέραιο (εσωτερικά είναι πραγματικός double), και τέλος το Α$() δίνει αλφαριθμητικό.  Ο διερμηνευτής δίνει προτεραιότητα στους πίνακες με το ίδιο όνομα. Τις συναρτήσεις μπορούμε να τις καλέσουμε με τις δυο συναρτήσεις Συνάρτηση() και Συνάρτηση$(). Η αν ξέρουμε ότι έχουμε πίνακα με το ίδιο όνομα βάζουμε το χαρακτήρα  * (παλαιότερα ήταν το @) μετά την αριστερή παρένθεση:
Πίνακας Α(10)=30
Κάνε Α(χ)=χ**2
Τύπωσε Α(3) \ τυπώνει 30
Τύπωσε Συνάρτηση("Α",3) \\ 9
Τύπωσε Α(* 3) \\ 9

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


Συνάρτηση ΈναςΠίνακας {
      Καθαρό Α$ \\ και έτσι ορίζουμε μια μεταβλητή
      Ενώ όχι κενό {
              Αν εινγρ τότε {
                  Α$=Α$+Παράθεση$(γραμμα$)
            } Αλλιώς {
                  Δες οκ {
                        Α$=Α$+γραφη$(αριθμός," #")
                    }
                  Αν όχι οκ τότε Α$=Α$+γραφη$(0, " #")
            }
      }
      \\ θυσιάζουμε το στοιχείο 0 για να είναι αριθμός πάντα
      \\ αφού η συνάρτηση θέλει το πρώτο στοιχείο αριθμό
      \\ και ίσως να μην έχουμε περάσει τίποτα
      Αν Α$="" τότε {
            Πίνακας Α(1)=0
            =Α()
      } αλλιώς {
            =παραμ(" 0"+Α$)
      }
}
Πίνακας Α(), Α1()
Α()=ΈναςΠίνακας(1,2,"Γεια Χαρά",3)
Ένωσε Α() στο Α$()
Τύπωσε Α(2), Α$(3)
Α1()=ΈναςΠίνακας()
Τύπωσε Α1(0)




Βλέπουμε ότι μια συνάρτηση μάζεψε τιμές και αντί να τις βάλει σε μεταβλητές τις έβαλε με ένα τρόπο σε ένα αλφαριθμητικό και τις πέρασε σαν να τις γράφαμε στο "=" στην επιστροφή της συνάρτησης (έχουμε δει ότι όλες οι συναρτήσεις μπορούν να επιστρέφουν παραπάνω από μια τιμή, και αυτό το κάνουν με πίνακα). Αν δεν δώσουμε τιμές τότε χωρίς το Αν Α$="" θα επέστρεφε μια τιμή, το 0 και όχι πίνακα. θέλουμε όμως να επιστρέφει πίνακα κάθε φορά και το κάνουμε αυτό δίνοντας στη περίπτωση που δεν έχουμε τιμές έναν πίνακα με ένα στοιχείο, με τιμή μηδέν.

Μπορούμε να συνεχίσουμε με αυτές τις εντολές:
Βάλε Α()
\\ χωρίς το παρακάτω θα έχουμε λάθος στην Διάβασε Α()
\\ Ο διερμηνευτής δεν αντιγράφει τον πίνακα Α()...στον εαυτό του, τον πίνακα Α()!
Πάνω : Φέρε 2 : Πέτα
Α()=ΈναςΠίνακας(1000,3452,"Γεια Χαρά και πάλι")
Τύπωσε Α(2), Α$(3)
Διάβασε Α()
Τύπωσε Α(2), Α$(3)


Βάζουμε τον πίνακα Α() στο σωρό. Ζητάμε στο σωρό να φτιάξει ένα αντίγραφο. Ζητάμε να φέρει το δεύτερο στοιχείο στην κορυφή. Ζητάμε να το πετάξει!
Τώρα ο πίνακας Α() θα αλλάξει τιμές αντιγράφοντας τις τιμές του πίνακα. Δεν θα αλλάξει αντικείμενο. Θα δούμε το "Γεια Χαρά και Πάλι". Όμως στην Διάβασε Α() ο πίνακας αλλάζει άμεσα αντικείμενο. Δείτε ότι το Α$() δεν έχασε την αναφορά στο Α$(). Αν δεν είχαμε κάνει την Πάνω/Φέρε/Πέτα τότε η αναφορά του πίνακα στο σωρό θα έδειχνε τον πίνακα στο Α(), που θα έχει αλλάξει με το Α()=ΈναςΠίνακας(...) και στη Διάβασε θα του λέγαμε βάλε στην Α() μια αντιγραφή από τον εαυτό του!
Αυτό που είδαμε είναι στην ουσία αντιγραφή τιμών σε πίνακα από πίνακα η οποία φαίνεται άμεσα και σε όσους πίνακες έχουμε συνδέσει (με την Ένωση)
Είδαμε επίσης ότι μπορούμε να περνάμε τιμές σε συναρτήσεις και να γίνονται παράμετροι με όνομα ή να χρησιμοποιούνται άμεσα, χωρίς όνομα.

Νεότερη έκδοση:

Πίνακας Α()
Α()=(1,2,"Γεια Χαρά",3)
// μας βάζει δείκτες από 0 έως 3
Πίνακας Α(1 έως Μήκος(Α()))
// αλλάξαμε δείκτες από 1 έως 4 χωρίς να σβήσουμε τα στοιχεία
Ένωσε Α() στο Α$()
Τύπωσε Α(2)=2, Α$(3)="Γεια Χαρά"
Μ=Α()
// Η χρήση του δείκτη σε πίνακα, αλλάζει τη βάση σε 0
// χωρίς να πειράξει τον πίνακα
Τύπωσε Μ#Τιμή(1)=2, Μ#Τιμή$(2)="Γεια Χαρά"
Τύπωσε Α(2)=2, Α$(3)="Γεια Χαρά"


7.1.4 Επαγωγικό Πέρασμα Τιμής!

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

Αν προσέξει κανείς τον κώδικα,  την εξαγωγή των Α_συν1() και Α_συν2() δεν την χρησιμοποιούμε. Η συνάρτηση "Κάτι" επιστρέφει τιμή πάνω σε μια Α που άλλαξε από μια από αυτές τις δύο, οι οποίες δόθηκαν υποτίθεται για εισαγωγή τιμής! Όμως έγινε αλλά μέσω τις αλλαγής μιας γενικής. Αυτός ο τρόπος, δηλαδή πέρασμα τιμής μέσω γενικής είναι αυτό που λέω εδώ "επαγωγικό πέρασμα τιμής". (η γενική Α θα διαγραφεί όπως και ότι άλλο ορίζουμε στο τμήμα με το πέρας εκτέλεσης αυτού)

Γενική Α=100
Συνάρτηση Α_συν1 {
            Α++
            \\ αν δεν επιστρέψουμε τιμή θα δοθεί το 0
}
Συνάρτηση Α_συν2 {
            Α+=2
}
Συνάρτηση Κάτι {
      =Α**2
}


Τύπωσε Κάτι(Α_συν1()), Α
Τύπωσε Κάτι(Α_συν2()), Α
Τύπωσε Κάτι(Α_συν1()), Α
Τύπωσε Κάτι(Α_συν2()), Α


ή θα μπορούσε να φτιάξει αυτό (η Οκν$()  έχει αναφερθεί στο τεύχος 8, στην παρ. 4.9). Η Α δεν είναι πια γενική, και οι συναρτήσεις που έχουν γίνει ανώνυμες έχουν την ιδιαιτερότητα όταν εκτελεστούν να βλέπουν ονόματα (όχι όμως σωρό) από το τμήμα/συνάρτηση που δημιουργήθηκαν (η Οκν$() το κάνει αυτό). Θα μπορούσαμε να είχαμε μια γενική Α αλλά οι συναρτήσεις αυτές δεν θα την έβλεπαν. Επιπλέον μπορούμε να στείλουμε τα αλφαριθμητικά που κρατάνε τις συναρτήσεις

Α=100
Συνάρτηση Α_συν1 {
            Α++
}
Συνάρτηση Α_συν2 {
            Α+=2
}
Συνάρτηση Κάτι {
      =Α**2
}
Κάτι$=Οκν$(&Κάτι())
Α_συν1$=Οκν$(&Α_συν1())
Α_συν2$=Οκν$(&Α_συν2())
Τύπωσε Συνάρτηση(Κάτι$, Συνάρτηση(Α_συν1$)), Α
Τύπωσε Συνάρτηση(Κάτι$, Συνάρτηση(Α_συν2$)), Α
Τύπωσε Συνάρτηση(Κάτι$, Συνάρτηση(Α_συν1$)), Α
Τύπωσε Συνάρτηση(Κάτι$, Συνάρτηση(Α_συν2$)), Α


Συνεχίζω το παραπάνω:
Α=100
Τμημά ΔοκιμασέΜε {
      Διάβασε &Α(), &Β(), &Γ()
      \\ εδώ η Α είναι άγνωστη
      Τύπωσε Α(Β())
      Τύπωσε Α(Γ())
      Τύπωσε Α(Β())
      Τύπωσε Α(Γ())
      Τύπωσε Έγκυρο(Α) \\0
}
ΔοκιμασέΜε Κάτι$, Α_συν1$, Α_συν2$


Τώρα έστειλα τις ανώνυμες συναρτήσεις στο τμήμα ΔοκιμασέΜε και εκεί τους έδωσα όνομα. Η Α δεν υπάρχει στο τήμα ΔοκιμασέΜε, Όμως και οι τρεις συναρτήσεις βλέπουν την Α (και οι Β και Γ την αλλάζουν) που είναι τοπική στο τμήμα που κάλεσε την ΔοκιμασέΜε()
Αυτό λέγεται κλείσιμο ή Closure, και η Μ2000 μπορεί να το κάνει προς τα κάτω σωστά αλλά όχι προς τα πάνω, δηλαδή να στείλει την Κάτι$ ως επιστροφή από το τμήμα - θα δούμε πώς ένα τμήμα επιστρέφει τιμές παρακάτω-  αλλά όταν θα τρέξει, η Α δεν θα υπάρχει, και θα βγει λάθος.

7.1.5 Παράδειγμα με Ομάδα (Αντικείμενο)


Ομάδα Άλφα {
Ιδιωτικό:
      Α=100
      Συνάρτηση Α_συν1 {
                  ++
      }
      Συνάρτηση Α_συν2 {
                  +=2
      }
      Συνάρτηση Κάτι {
            =**2
      }
Δημόσιο:
      Τμήμα ΠάρεΑ {
            Διάβασε .Α
      }
      Συνάρτηση Κάτι_1 {
            =.Κάτι(.Α_συν1())
      }
      Συνάρτηση Κάτι_2 {
            =.Κάτι(.Α_συν2())
      }
}
Για Άλφα {
      Τύπωσε .Κάτι_1()
      Τύπωσε .Κάτι_2()
      Τύπωσε .Κάτι_1()
      Τύπωσε .Κάτι_2()
}
Άλφα.ΠάρεΑ 100
Τμημά ΔοκιμασέΜε {
      Διάβασε δείκτης$
      Για δείκτης$ {
            Τύπωσε .Κάτι_1()
            Τύπωσε .Κάτι_2()
            Τύπωσε .Κάτι_1()
            Τύπωσε .Κάτι_2()
      }


}
ΔοκιμασέΜε &Άλφα


Εδώ έχουμε ένα αντικείμενο και το περνάμε μόνο με ισχνή αναφορά. Θα ήταν κανονική έτσι:

Τμημά ΔοκιμασέΜε {
      Διάβασε &Βήτα
      Για Βήτα {
            Τύπωσε .Κάτι_1()
            Τύπωσε .Κάτι_2()
            Τύπωσε .Κάτι_1()
            Τύπωσε .Κάτι_2()
      }
}


Δηλαδή με την διάβασε καθορίζουμε αν κάνουμε μια αναφορά κανονική άμεσα ή αν θα την κρατήσουμε ως ισχνή (γράφοντάς την σε ένα αλφαριθμητικό), για μελλοντική χρήση. Αν καλούσαμε μια φορά την Δοκίμασέ με τότε ο δεύτερος τρόπος, της κανονικής αναφοράς θα ήταν οκ, αλλά επειδή με αυτό το τρόπο δημιουργούμε τα στοιχεία της ομάδας μέσα στο τμήμα ΔοκίμασέΜε, σε μια επαναληπτική διαδικασία 100 φορών θα είχαμε 100 δημιουργίες μελών της ομάδας Βήτα, ενώ με το Δείκτης$ θα έχουμε 100 φορές μόνο το Δείκτης$. Μια άλλη διαφορά είναι ότι ο δείκτης βλέπει σαν γενικό αυτό που δείχνει άρα περάσματα τιμών σε απλές μεταβλητές ακολουθούν τους κανόνες των γενικών με "<=" για αντικατάσταση τιμών. Επιπλέον με την χρήση δείκτη μπορούμε να περάσουμε στοιχείο πίνακα που δεν μπορεί να βγει κανονική αναφορά (οι κανονικές έχουν σχέση με τα ονόματα, και τα στοιχεία πίνακα, μόνο στο πίνακα έχουν όνομα). Αν ο δείκτης δείχνει κάτι που δεν υπάρχει θα το καταλάβουμε στο Για ενώ αν δεν υπάρχει στην περίπτωση με τη χρήση της Βήτα θα το καταλάβουμε στην Διάβασε &Βήτα. Ουσιαστικά κάθε φορά που χρησιμοποιούμε την ισχνή αναφορά, γίνεται έλεγχος, και αυτό στην περίπτωση με την Βήτα γίνεται μια φορά. Αυτό δεν σημαίνει ότι χρησιμοποιώντας την Βήτα δεν γίνεται έλεγχος αν υπάρχει η Βήτα! Ο διερμηνευτής δουλεύει με ελέγχους, τόσο στα ονόματα όσο και στους δείκτες πινάκων.

Το παράδειγμα με κλάση, και δείκτη σε Ομάδα. Έχει μπει και η Διαγραφή { } που εκτελείται πριν διαγραφεί το αντικείμενο, επειδή τελείωσαν οι δείκτες που το δείχνουν. Στην ουσία ακόμα υπάρχει δείκτης αλλά όχι από την μεριά του χρήστη. Αν έχουμε επώνυμο αντικείμενο όπως η Ομάδα Άλφα στο προηγούμενο παράδειγμα τότε δεν καλείται η Διαγραφή, γιατί το αντικείμενο διαγράφεται στο τέλος εκτέλεσης του τμήματος, και επιπλέον δεν έχει δεύτερο δείκτη (είναι μονού, που γνωρίζει μόνο ο διερμηνευτής). Ακόμα και πάρουμε ένα δείκτη με μια ΜΜ->Αλφα δεν θα έχουμε αληθινό δείκτη αλλά ισχνή αναφορά στην ομάδα . Στο παρακάτω όμως το ΜΜ=Αλφα φτιάχνει δείκτη, γιατί το Αλφα είναι δείκτης. Η διαφορά ανοικτού και κλειστού αντικειμένου, είναι ότι το ανοικτό είναι συνδεδεμένο με το τμήμα, ενώ το κλειστό είναι ανεξάρτητο. Για να χρησιμοποιήσουμε το κλειστό ο διερμηνευτής το ανοίγει πρόσκαιρα. δηλαδή το συνδέει όπως το ανοικτό, κάνει ότι έχει να κάνει και το κλείνει. Τα ανοιχτά αντικείμενα τύπου Ομάδα έχουν το πλεονέκτημα να μπορούν να περάσουν με αναφορά, ιδιότητες, μεταβλητές δημόσιες, συναρτήσεις. Επίσης μπορούμε να τα ορίσουμε με γεγονότα. Τα κλειστά μπορούν να μετακινηθούν (λέγονται και πτητικά), να μπουν σε πίνακες, σωρούς τιμών, λίστες και ουρές. Στην ουσία έχουμε τέσσερα πράγματα που είναι αντικείμενο ομάδα: Ανοικτό, Κλειστό, Δείκτης σε Ανοικτό, Δείκτης σε Κλειστό. Οι δείκτες χειρίζονται με τον ίδιο τρόπο, είτε σε ανοικτό είτε σε κλειστό αντικείμενο. Σε κάποιες γλώσσες το ανοικτό είναι η στατική κλάση (δεν δίνει άλλα αντικείμενα). Στη Μ2000 όλα τα αντικείμενα τύπου Ομάδα δίνουν αντίγραφο. Για να πάρουμε αντίγραφο από δείκτη σε ομάδα χρειάζεται η Ομάδα(Δείκτης1) ή αν η ομάδα επιστρέφει τιμή αλφαριθμητική το Ομάδα$(Δείκτης2). Αντίγραφο σημαίνει να πάρουμε κάτι που διατηρεί την κατάσταση (state) του αντικειμένου. Παρόλα αυτά ενδέχεται κάποια κατάσταση να έχει δείκτη οπότε θα πάρουμε αντίγραφο του δείκτη. Όταν όμως φτιάχνουμε Κλάσεις με περιεχόμενες ομάδες ανοικτές, τότε θα πάρουμε αντίγραφο αυτών των ομάδων (και όχι δείκτες). Εδώ είναι η σημασία του ανοικτού αντικειμένου στα ένθετα αντικείμενα ομάδα σε αντικείμενο ομάδα, όπου η αντιγραφή τους γίνεται σε βάθος (ενώ μέσω δεικτών η αντιγραφή λέγεται ρηχή και πρέπει κάποιος να φτιάξει επιπλέον λογική για να την κάνει σε βάθος).


Κλάση Άλφα {
Ιδιωτικό:
      Α=100
      Συνάρτηση Α_συν1 {
                  ++
      }
      Συνάρτηση Α_συν2 {
                  +=2
      }
      Συνάρτηση Κάτι {
            =**2
      }
Δημόσιο:
      Τμήμα ΠάρεΑ {
            Διάβασε
      }
      Συνάρτηση Κάτι_1 {
            =.Κάτι(.Α_συν1())
      }
      Συνάρτηση Κάτι_2 {
            =.Κάτι(.Α_συν2())
      }
      Διαγραφή {
            Τύπωσε "Μόλις διαγράφτηκα",
      }
}
Άλφα->Άλφα()
Για Άλφα {
      Τύπωσε .Κάτι_1()
      Τύπωσε .Κάτι_2()
      Τύπωσε .Κάτι_1()
      Τύπωσε .Κάτι_2()
}
Άλφα=>ΠάρεΑ 100
Τμημά ΔοκιμασέΜε(Δ ως Άλφα) {
      Για Δ {
            Τύπωσε .Κάτι_1()
            Τύπωσε .Κάτι_2()
            Τύπωσε .Κάτι_1()
            Τύπωσε .Κάτι_2()
      }


}
ΔοκιμασέΜε Άλφα
// και αυτά γυρίζουν μηδενικό δείκτη (Null)
// Άλφα->Δείκτης()
// Άλφα->0&
Άλφα=Δείκτης()


// Null ή Μηδενικός γυρίζει το Δείκτης() ή Pointer()
Τύπωσε Άλφα είναι τύπος Μηδενικός = Αληθές
Τύπωσε Άλφα είναι τύπος Null = Αληθές

Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.