Σάββατο, 29 Απριλίου 2017

Αναθεώρηση 16 (Έκδοση 8.7) - Προσθήκη Επεξηγήσεων!

Βελτιώθηκε η ταχύτητα στο χειρισμό των αντικειμένων.
Εδώ έχουμε μια κλάση, που παράγει αντικείμενα. Το τμήμα Class: δεν θα περάσει στις παρουσίες των αντικειμένων.
Χρησιμοποιούμε ένα αντικείμενο Σωρός (ειδική στοίβα) και εκεί βάζουμε μερικά αντικείμενα. Έχουμε δυο ρουτίνες ταξινόμησης, μια Selection Sort  ή ταξινόμηση με επιλογή (εδώ την λέμε StackSort) και η άλλη είναι η quicksort.
Στην πρώτη ρουτίνα ταξινόμησης χρησιμοποιείται σωρός με επισροφές τιμών απευθείας σε στοιχεία. Ο σωρός είναι συνδεδεμένη λίστα, και κανονικά με την Βάλε ή Push βάζουμε στη κορυφή και με την Σειρά ή Data βάζουμε στο πυθμένα. Η Διάβασε ή Read διαβάζει πάντα από την κορυφή (και πετάει την τιμή)
Με την χρήση του StackItem() ή ΤιμήΣωρού()  (και StackItem$() ή ΤιμήΣωρού$() για αλφαριθμητικά), διαβάζουμε χωρίς να πετάμε τιμές. Αν θέλουμε μπορούμε με την Επιστροφή να επιστρέψουμε τιμές σε θέσεις (να τις αλλάξουμε δηλαδή). Η εντολή επιστροφή αλλάζει πολλές τιμές αν θέλουμε (παίρνει λίστα). Δείτε όμως ότι για να λειτουργήσει θέλει δείκτη σε σωρό. Μπορούμε να πάρουμε τον τρέχον σωρό σε ένα δείκτη με αυτό Αλφα=[]  (το [] είναι ο τρέχον σωρός), και ο τρέχον σωρός θα αδειάσει. Μπορούμε να επιστρέψουμε τις τιμές από το Αλφα με την Σωρός Άλφα (θα μπούνε οι τιμές στο τέλος του σωρού, οπότε αν είναι άδειος ο τρέχουν θα έχει τις τιμές του Άλφα, και ο Άλφα θα αδειάσει).






Class M {
       x=10, y=30
      Function comp (mm) {
            = Compare(.x,mm.x)
      }
      operator ">"  (mm) {
            Push .x>mm.x
      }
      value {
            =.x*.y
      }
Class:
      Module M (.x,.y) {}
}
N=Stack:=M(10,30), M(4,15), M(50,60),M(3,15), M(33,16), M(34,15), M(33,16), M(4,15), M(10,30), M(54,15), M(50,60),M(13,15), M(33,16), M(124,15) , M(10,30), M(4,15), M(50,60),M(13,15), M(33,16), M(4,15), M(33,16), M(4,15), M(10,30), M(54,15), M(50,60),M(23,15), M(33,16), M(24,15)
Inventory Const="Ascending":=1, "Descending":=-1
Profiler
If Len(N)>1 then SortStack(each(N, 1, Len(N)-1),Const("Ascending"))
Print timecount
Print "Press Any Key, for list - sorted by second column from left"

A$=Key$
Print "xxxxxxxxxxxxxxxxxxxxxxxxxxXXXXxxxXXXXxxxxxxxx"
ShowN(Each(N))

N=Stack:=M(10,30), M(4,15), M(50,60),M(3,15), M(33,16), M(34,15), M(33,16), M(4,15), M(10,30), M(54,15), M(50,60),M(13,15), M(33,16), M(124,15) , M(10,30), M(4,15), M(50,60),M(13,15), M(33,16), M(4,15), M(33,16), M(4,15), M(10,30), M(54,15), M(50,60),M(23,15), M(33,16), M(24,15)
Profiler
Stack N {
      quicksort(1, Len(N), Const("Ascending"))
}
Print timecount
Print "Press Any Key, for list - sorted by second column from left"

A$=Key$
Print "xxxxxxxxxxxxxxxxxxxxxxxxxxXXXXxxxXXXXxxxxxxxx"
ShowN(Each(N))
Sub SortStack(Nrep1, cc)
While Nrep1 {
      Nrep2=Each(Nrep1, Nrep1^+1)
            Let temp1=stackitem(Nrep1)
            ok=FALSE
            While Nrep2 {
                              let temp2=stackitem(Nrep2)
                              If compare(temp1.x,temp2.x)=cc then {
                              return Nrep2, Nrep2^+1:=Group(temp1)
                              let temp1=group(temp2)
                              ok=TRUE
            }
           If ok then return Nrep1, Nrep1^+1:=Group(temp1)
      }
}
End Sub
Sub ShowN(Nrep)
      While Nrep {
                 Let temp=stackitem(Nrep)
                  Print temp, temp.x, temp.y, Nrep^+1
      }
End Sub
Sub quicksort(first, last, cc)
      Local thing(1), i=first, Limit=last+1
      If Limit >2 Then Shift (Limit+i) Div 2
      Read thing(0)
      Limit--
      For thing(0) {
            While i<Limit {
                  If .comp(stackitem(i))=-cc then {
                        Limit--
                        If i>1 Then Shift i
                        ShiftBack Limit
                  }  Else i++
            }
            If i>Limit Then i=Limit
            Push group(This)
            }
     dim thing()
      ShiftBack i
      If i>first Then quicksort(first,i-1, cc)
      If last>i Then quicksort(i,last, cc)
End Sub


Μια εξήγηση για το thing(1) και λίγα λόγια για τα αντικείμενα.  Εκτός από την Πϊνακας (Dim) για να ορίσουμε πίνακες μπορούμε να ορίζουμε και με την Local (Τοπική ή Τοπικές) ή και την Global (Γενική ή Γενικές). Δεν έχουμε όμως τα ίδια επιπλέον που μας δίνει η Πίνακας (πχ την αλλαγή βάσης), αλλά μπορούμε εκ των υστέρων να την χρησιμοποιήσουμε (όταν θα υπάρχει ήδη το αντικείμενο - εσωτερικά οι πίνακες είναι αντικείμενα στη Μ2000).
Εδώ στην quicksort θέλουμε να διαβάσουμε το αντικείμενο σε θέση πίνακα. Όταν γίνεται αυτό το αντικείμενο είναι κλειστό, δηλαδή περιέχει οτιδήποτε μόνο για το ίδιο. Αν το διαβάσουμε με όνομα, τότε δημιουργείται το λεγόμενο ανοικτό και όλα τα μέλη γίνονται ταυτόχρονα μέλη του τμήματος που διαβάστηκε (οι ρουτίνες είναι μέρος του τμήματος, στο οποίο ότι δημιουργούμε διαγράφεται). Επειδή θέλουμε να καλέσουμε με αναδρομή την quicksort μας βολεύει το αντικείμενο να μην παίρνει χώρο στις λίστες μεταβλητών/συναρτήσεων, ως ανοικτό, και να ανοίγει μόνο όταν χρειάζεται. Το πρόσκαιρο άνοιγμα το κάνει η For thing(0) { } και έτσι εντός του μπλοκ το .comp() σχετίζεται με αυτό το αντικείμενο.
Η δυσκολία (που δεν φαίνεται με μια ματιά) βρίσκεται στο ότι έχουμε το αντικείμενο έτσι φτιαγμένο ώστε να γυρνάει τιμή (το Χ*Υ). Η Stackitem() όμως δεν γυρνάει τιμή αλλά ένα αντίγραφο του αντικειμένου (δεν δίνει δείκτη στο αντικείμενο ομάδα, ενώ σε άλλα αντικείμενα που τα χρησιμοποιούμε με δείκτη προς αυτά όντως δίνει δείκτη).
Επειδή βγάζουμε από την λίστα (σωρός τιμών) ένα αντικείμενο και το βάζουμε στην Thing(0) (ένα στοιχείο, με βάση το 0, άρα θα είναι στην θέση 0), θα πρέπει να το βάλουμε πάλι στη θέση του. Αν κάναμε αυτό Βάλε Thing(0) θα έδινε την τιμή X*Y και όχι το αντικείμενο. Η Ομάδα() ή Group() θέλει ένα ανοικτό αντικείμενο και αφού το βρει δίνει το αντίγραφό του σε κλειστό (μαζεύει ότι έχει μέσα στο χώρο του αντικειμένου, ενώ στο ανοικτό, ο χώρος του αντικειμένου είναι μια λίστα με ονόματα και θέσεις στο χώρο μεταβλητών/συναρτήσεων, χωρίς τιμές). Δίνουμε το This (Αυτό) που ο διερμηνευτής γνωρίζει ότι είναι το ανοικτό αντικείμενο που έβγαλε η For Thing(0) { }. Θα μπορούσαμε να τo περάσουμε και με  αναφορά πχ Τμήμα1 &Αυτό σε ένα τμήμα Τμήμα1 (αρκεί εκεί να υπάρχει η Διάβασε &έναόνομα). Έτσι βάζουμε στο σωρό το Group(This) με την Push Group(This), ως αντίγραφο του This. Μόλις τερματίσει το μπλοκ For Thing(0) { } αυτόματα ξανακλείνει το αντικείμενο, πετάει το παλιό στο Thing(0) και βάζει το νέο (στο πίνακα έχουμε Variant γιατί αυτός ο τύπος μπορεί να πάρει δείκτες προς αντικείμενα, αλλά και τιμές όπως double ή τύπου string).
Αν έχουμε βάθος κλήσεων έστω 10 στην quicksort (την ρουτίνα όπως έχουμε εδώ) τότε το τμήμα θα έχει δέκα πίνακες Thing(0) και ο ενεργός θα είναι ο τελευταίος. Κάθε φορά που κάνουμε επιστροφή από την ρουτίνα, καθαρίζονται οι λίστες μεταβλητών/συναρτήσεων, στο σημείο που ήταν πριν την κλήση.
Η Μ2000 δεν τοποθετεί τις μεταβλητές και τις συναρτήσεις στην στοίβα εκτέλεσης. Οι λίστες μεταβλητών και συναρτήσεων είναι δυναμικοί πίνακες με λειτουργία συνάρτησης κατακερματισμού (για να βρίσκει γρήγορα τα ονόματα), με την ιδιομορφία να αυξομειώνονται (όχι υποχρεωτικά και ο χώρος τους κάθε φορά), πάντα από το τέλος, το πιο πρόσφατο, και να περιέχουν ίδια κλειδιά (ίδια αναγνωριστικά). Με αυτόν τον τρόπο πετυχαίνεται η σκίαση μεταβλητών. Το πραγματικό όνομα μιας μεταβλητής έχει να κάνει με το όνομα που βλέπουμε και το πρόθεμα που παίρνουν από το τμήμα που βρίσκονται. Δεν μας απασχολεί αυτό, αφού δουλεύει, αλλά έχει σημασία να γνωρίζουμε ότι αντικείμενα που είναι σε πίνακες έχουν κρυφό όνομα που αποδίδεται από το σύστημα όταν ανοίγουν. Το άνοιγμα σημαίνει να περαστούν τα ονόματα μεταβητών/συναρτήσρων στις λίστες ώστε να μπορούν να χρησιμοποιηθούν. Εδώ δεν έχουμε κάποια διεπαφή (interface) να παίρνει το όνομα της συνάρτησης της ομάδας και να το αναζητεί σε αυτό, αλλά απευθείας καλείται η συνάρτηση ως υπάρχουσα σαν όλες τις άλλες. Στην κλήση όμως η συνάρτηση ενημερώνει ότι ανήκει σε αντικείμενο με συγκεκριμένο πρόθεμα, οπότε οι μεταβλητές .Χ και .Υ θα πάρουν το σωστό πρόθεμα (και θα βρεθούν άμεσα στη λίστα μεταβλητών). Έτσι οι ομάδες (Groups) στην M2000 δεν έχουν Διεπαφή/interface, ξεχωριστό από το χρήστη, παρά μόνο ένα βασικό (υποχρεωτικά) που διαχειρίζεται εσωτερικά ο διερμηνευτής. Οι κλάσεις είναι συναρτήσεις που παράγουν ομάδες. Έτσι υπάρχει η νοητή διεπαφή, τα μέλη της ομάδας. Θα βγει λάθος κατά την εκτέλεση αν ζητάμε ένα μέλος που δεν υπάρχει. Οι ομάδες μπορούν να αυξάνουν τα μέλη τους, ενώ δεν υπάρχει διαγραφή μελών. Αυτό που υπάρχει είναι η συγχώνευση,  δηλαδή έχουμε μια ομάδα Α και θέλουμε να έχει επιπλέον τα μέλη της Β, μπορούμε με το Α=Β να δώσουμε αντίγραφο μελών του Β στο Α (αν το Β και το Α δεν έχουν Αξίες, δεν λειτουργούν ως μεταβλητές με τιμές αριθμητικές ή αλφαριθμητικές). Ή μπορούμε να έχουμε μια νέα ομάδα Ζ και σε αυτήν να βάλουμε το Ομαδα(Α) και Ομάδα(Β), διαδοχικά: Ζ=Ομάδα(Α) και Ζ=Ομάδα(Β), και έτσι θα έχουμε την Ομάδα Ζ με τα μέλη του Α και του Β (αν το Β έχει κάποια ίδια μέλη με το Α τότε το Ζ θα εχει μια φορά αυτά τα μέλη με τις τελευταίες τιμές, αυτές του Β). Επειδή η Μ2000 έχει την δυνατότητα δημιουργίας πρόσκαιρων ορισμών, τόσο ως τοπικές σε  τμήμα/συνάρτηση/ρουτίνα όσο και στα μπλοκ με Για αντικείμενο { } (και σαν γενική μορφή υπάρχει το Για Αυτό { }) να έχουμε ομάδες όπως η Ζ να εξυπηρετούν το σκοπό μας και μετά βάζουμε στο Α ας πούμε ένα τμήμα που θα διαβάζει με αναφορά το Ζ και θα παίρνει τις νέες τιμές που θέλουμε να κρατήσουμε μετά τη διαγραφή του (το Ζ ας πούμε είναι προσωρινό).
Με την συγχώνευση μελών η Μ2000 πετυχαίνει να δημιουργεί ομάδες από άλλες ομάδες, άρα κατά μια έννοια να προσθέτει λειτουργικότητα. Στη Μ2000 όπως μπορούμε να έχουμε τμήματα/συναρτήσεις/ρουτίνες σε τμήματα/συναρτήσεις, και τμήματα/συναρτήσεις σε ρουτίνες (μπορούμε να έχουμε ρουτίνες σε ρουτίνες, αλλά στην ουσία δεν έχει νόημα αφού οι ρουτίνες έχουν θέαση σε όλο το τμήμα απ όπου καλούνται, άρα κάπου θα βρούμε χώρο να βάλουμε κάποιες άλλες και όχι ειδικά μέσα σε μια ρουτίνα), έτσι και στις ομάδες μπορούμε να έχουμε ένα δένδρο ομάδων (μπορούμε να κάνουμε συγχωνεύσεις σε ομάδες που βρίσκονται σε άλλες ομάδες, αρκεί να μην γυρνούν ή δέχονται τιμή ως μεταβλητές). Μια ομάδα μπορεί να έχει οτιδήποτε εκτός από ρουτίνες (ρουτίνες μόνο τα τμήματα και οι συναρτήσεις έχουν, και αυτά όμως που βρίσκονται σε ομάδες). Μπορούμε ακόμα να έχουμε κλάσεις σε ομάδες, για να δημιουργούν δικές τους ομάδες (οι ομάδες επιστρέφονται ως κλειστά αντικείμενα και από συναρτήσεις, αλλά τοποθετούνται σε πίνακες, καταστάσεις  (λίστες με κλειδί) και σωρούς (ειδικές στοίβες τύπου συνδεδεμένης λίστας σε μια απλή διάταξη γραμμής, όπου η μετακίνηση θέσης είναι ανέξοδη, σε χρόνο και πόρους)
Αξίζει να αναφερθεί ότι μπορούμε σε κάθε θέση σε πίνακα, κατάσταση, σωρό να έχουμε οτιδήποτε. Ένας πίνακας δηλαδή μπορεί να έχει στις θέσεις του άλλους πίνακες και αυτοί να έχουν σωρούς, και οι σωροί να έχουν ομάδες. 'Η να έχουμε πίνακες με καταστάσεις (δουλεύουν με πίνακα κατακερματισμού, άρα με γρήγορη αναζήτηση) και σε κάθε στοιχείο κατάσταση να έχουμε πίνακα ή σωρό ή άλλη κατάσταση.
Τα αντικείμενα σωρός, κατάσταση, και ο λεγόμενος αυτόματος πίνακας (είδος πίνακα) δουλεύονται με δείκτη (αλλά στην τιμή του δεν έχουμε πρόσβαση), αλλά μεταβιβάζεται. Αυτό σημαίνει όμως ότι μπορεί μια κατάσταση Α να έχει σε στοιχείο της δείκτη στον εαυτό της ή σε άλλη Β όπου εκεί να υπάρχει δείκτης στην Α. Για το λόγο αυτό υπάρχει σύστημα που γνωρίζει πώς θα "Σκουπίσει" στη περίπτωση διαγραφής (σε προσωρινές-τοπικές), και αυτό λέγεται συλλέκτης σκουπιδιών. Η εντολή Λίστα αναφέρει αν υπάρχουν αντικείμενα με πολλαπλούς δείκτες προς αυτά. Ο καθαρισμός γίνεται αυτόματα, αλλά γίνεται και με το Clear ή Καθαρό που σβήνει μεταβλητές και κάνει και έλεγχο για καθαρισμό (αν χρειάζεται).