Πέμπτη 16 Φεβρουαρίου 2017

Αναθεώρηση 19 Έκδοση 8.2

Διορθώθηκαν μερικά Bug (και έγινε προσπάθεια να βρεθεί και άλλο, και δεν καρποφόρησε..ακόμα)
Στο παράδειγμα παρακάτω...βάζουμε ένα αντικείμενο ομάδα, σε μια κατάσταση και την κατάσταση σε ένα πίνακα. Ενώ οι πίνακες και οι ομάδες αντιγράφονται, οι καταστάσεις δεν αντιγράφονται απλά περνάει μια αντιγραφή ενός δείκτη που δείχνει την κατάσταση. Αυτό θα το λέγαμε ως αναφορά στη κατάσταση. Ο λόγος που γίνεται αυτό είναι γιατί η κατάσταση θα έχει πολλά στοιχεία και μια αντιγραφή θα κοστίζει σε χρόνο (φόρτος).
Μια Κατάσταση μπορεί να έχει μόνο κλειδιά, ή να βάλουμε και σε όποιο κλειδί θέλουμε κάτι, ένα αριθμό, ένα αλφαριθμητικό, μια συνάρτηση λάμδα, ένα πίνακα, μια ομάδα, ένα πίνακα με ομάδες ή και ότι άλλο θέλουμε, ακόμα μπορούμε να βάλουμε μια άλλη Κατάσταση (πάλι όμως θα περάσει σαν αναφορά).
Για να διαβάσουμε κάτι από τη κατάσταση είναι απλή υπόθεση. Αν την βάλουμε σε πίνακα, συνεχίζει να είναι απλή υπόθεση. Όμως για να αλλάξουμε κάτι, ενώ είναι σε πίνακα δεν είναι τόσο απλό. Επειδή έχει έμμεση αναφορά, ο τρόπος που έχει επιλεχθεί είναι με χρήση μιας άλλης κατάστασης που παίρνει την αναφορά στην καταχωρημένη στο πίνακα. Κάνουμε αλλαγές μέσω αυτής και στο τέλος απλά καθαρίζουμε με την Καθαρό ΌνομαΚατάστασης που αφήνει μια κενή νέα κατάσταση. Ο πίνακας συνεχίζει να δείχνει την αναφορά ση κατάσταση που επεξεργαστήκαμε.Στο παράδειγμα και η τοπική Λ και η τοπική Ν θα "εξαφανιστούν" στην λήξη του Για Αυτό {} γιατί αυτό είναι το μπλοκ όπου όλοι οι ορισμοί μεταβλητών, πινάκων, ομάδων κ.α.α είναι προσωρινοί για το μπλοκ αυτό.

Για τον πίνακα Π και τη θέση 1 υπάρχει μια εντολή που κάνει τη Κατάσταση να "ξεκολλήσει", και αυτό είναι το 0. Όταν πάμε στην Ν την κατάσταση, βάζουμε το 0 στη θέση στον πίνακα απ΄όπου την πήραμε. Εδώ πρακτικά δεν μας βοηθάει κάπου αυτό. Θα βοηθούσε αν τρέχουν νήματα και κάποιο νήμα θέλει να αλλάξει κάτι στη Κατάσταση, γιατί τώρα απλά δεν θα την βρεί!


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

Κατάσταση Κ1
Ομάδα αβγ {
      μ=5
      Συνάρτηση φ { Διάβασε χ : =χ*10+ }
}
Τύπωσε αβγ.φ(20)
κλειδί$="Ναι"
\\ φορτώνουμε στη λίστα ένα αντίγραφο της ομάδας
Προσθήκη Κ1, κλειδί$:=αβγ
\\ Ο διερμηνευτής επιλύει αυτό
Τύπωσε Κ1("Ναι").φ(20)
\\ και αυτό
Κ1("Ναι").μ++
Τύπωσε Κ1("Ναι").μ \\ 6


Πίνακας Π(10)
\\ η Κατάσταση πάντα γράφεται με αναφορά
\\ εδώ ο πίνακας κρατάει μια αναφορά στην κατάσταση Κ1
Π(1)=Κ1
Τύπωσε Π(1)("Ναι").φ(20), Π(1)("Ναι")
Για Αυτό {
      \\δεν έχουμε κάποια Λ στο κώδικα πριν, έστω ότι έχουμε: φτιάχναμε μια τοπική
      Τοπική Λ
      Κατάσταση Λ
      Λ=Π(1) \\ Τώρα θα δώσουμε μια αναφορά στο Ν (το Ν είναι κατάσταση
      Λ("Ναι").μ+=10
      \\ εδώ τελειώνει το Για Αυτό {}, και η Λ θα διαγραφεί (ο δείκτης στη Π(1) που είναι ίδιος με την Κ1)
     
}
\\ Απόδειξη
Τύπωσε Π(1)("Ναι") \\ 16
Τύπωσε Κ1("Ναι").μ \\ 16
Τύπωσε Μήκος(Κ1) \\ 1 στοιχείο
Καθαρό Κ1 \\ καθαρίζουμε τη κατάσταση, βάζοντας μια καινούργια μηδενική!
Τύπωσε Μήκος(Κ1) \\ 0
Τύπωσε Μήκος(Π(1)) \\ 1  η κατάσταση μένει εδώ ως έχει.
Τύπωσε Π(1)("Ναι") \\ 16
Για Αυτό {
      Τοπική Ν
      Κατάσταση Ν
      Ν=Π(1)
      Π(1)=0 \\ δεν παίρνει το μηδέν αλλά το Τίποτα
      Τύπωσε Τύπος$(Π(1)) \\ Nothing, παραμένει ένα "τίποτα"
      Π(1)=Ν \\ τώρα το βάλαμε στη θέση του1
      Τύπωσε Τύπος$(Π(1)) \\ Inventory (Κατάσταση)
}
\\ Σβήνουμε τον πίνακα
Πίνακας Π()
Λίστα
\\ την εντολή παρακάτω την δίνουμε για να αδειάσει η συλλογή σκουπιδιών.
\\ στην ουσία σβήνει τις κρατημένες αναφορές, και τις τυχόν κυκλικές
\\
Άδειασε Σκουπίδια

 

Τετάρτη 15 Φεβρουαρίου 2017

Αναθεώρηση 18 - Έκδοση 8.2

Διορθώθηκαν δυο πράγματα:
1) Στις λάμδα συναρτήσεις γίνεται έλεγχος για τις Καταστάσεις (τύπος Inventory, Κατάσταση) που μπορεί να έχουν κρατήσει (captured) κατά την διαγραφή τους ώστε να αποδεσμευτούν από τον συλλέκτη σκουπιδιών (garbage collector). Οι καταστάσεις (λίστες με κλειδί) περνούν με αναφορά, και η αναφορά περνάει και στον garbage collector.
Με την εντολή Λίστα (list) βλέπουμε τι μεταβλητές έχουμε τη δεδομένη στιγμή και αν έχουν κρατηθεί αναφορές στον συλλέκτη σκουπιδιών (δεν εμφανίζεται η αναφορά αν δεν έχουμε, ή εμφανίζεται "Αντικείμενα για διαγραφή και ο αριθμός τους"

 Φόρμα 60,40
δυαδ0$=λάμδα$ ->{
      Κατάσταση δυαδική_τιμή = 0:="0000",1:= "0001",2:= "0010", 3:="0011",4:= "0100", 5:="0101", 6:="0110", 7:="0111", 8:="1000", 9:="1001", "A":="1010", "B":="1011", "C":="1100", "D":="1101", "E":="1110", "F":="1111"     
      \\ η δυαδ$ είναι μια λάμδα συνάρτηση που συλλαμβάνει τη Κατάσταση δυαδική_τιμή
      \\ τα πρώτα κλειδιά έχουν ως αριθμοί. Η κατάσταση τα δέχεται και ως αριθμούς και ως γράμματα, γιατί τα κλειδιά τα κρατάει ως γράμματα εσωτερικά!
      = λάμδα$ δυαδική_τιμή->{
            Διάβασε μια_τιμή
            Αν Ταύτιση("Α") τότε {
                  Διάβασε από_εδώ
                 από_εδώ=2*(ακ(4-από_εδώ) υπολ 4+1)-1
            } Αλλιώς {
                  από_εδώ=1
            }
                  δεκαεξαδική$ = Δεκαεξ$( μια_τιμή, 4 )
            Εγγραφο Αα$
            Για ι = από_εδώ Εως Μήκος( δεκαεξαδική$ )
                  Αα$ =  δυαδική_τιμή$( Μεσ$( δεκαεξαδική$, ι, 1 ) )
            Επόμενο ι
            = Αα$
      }
}
δυαδ$=δυαδ0$()
Τύπωσε δυαδ$(12), 12
Τύπωσε δυαδ$(255,1), 255
Τύπωσε δυαδ$(256*256+255,2), 256*256+255
Τύπωσε δυαδ$(0xFF446688,4), 0xFF446688
Λίστα  \\ δείχνει τις μεταβλητές και στο τέλος λέει Αντικείμενα για καταστροφή 1 (και αυτό είναι η Κατάσταση, που είναι με αναφορά)
Βάλε δυαδ$ \\ βάζουμε στο σωρό ένα αντίγραφο
\\  όταν τερματίσει το πρόγραμμα δίνουμε τις εντολές
\\  Σωρός  (και βλέπουμε ότι υπάρχει ένα αντικείμενο λάμδα)
\\ Λίστα (και μας λέει ότι έχει ένα αντικείμενο για διαγραφή)
\\ έχουμε δυο δυνατότητες
\\ ή παίρνουμε τη λάμδα σε μια μεταβλητή (πρέπει να είναι τύπου αλφαριθμητικού, όπως φτιάξαμε τη λάμδα)
\\ Διάβασε δ$  : Τύπωσε δ$(123, 1) : λίστα  \\ παραμένει το ένα αντικείμενο
\\ Καθαρό : Λίστα  \\ τώρα δεν υπάρχει τίποτα
\\ ή αδειάζουμε το σωρό με την Άδειασε χωρίς να φτιάξουμε λάμδα συνάρτηση
\\ Άδειασε : Λίστα \\ τώρα έχει διαγραφεί και το αντικείμενο που κράταγε η λάμδα στο σωρό!



2) Διορθώθηκε και αυτό (είχε λάθος στο Read για τις λάμδα σε μεταβλητή string, κατά το διάβασμα από το σωρό)

a$=Lambda$->"Ok"
Print a$()
Push a$ \\ to stack
Read m$ \\ from stack to new variable
Print type$(m$), m$()
 

Τρίτη 14 Φεβρουαρίου 2017

Αναθεώρηση 17 (Έκδοση 8.2)

1) Πρόσθεσα δυο διευκολύνσεις στο σχηματισμό πινάκων.
Μια είναι η προσωρινή επιλογή βάσης (1 ή 0) που δεν επηρεάζει την τέχουσα επιλογή. Στη Μ2000 οι πίνακες από την έκδοση 8.2 αναθεώρηση 15μπορούν να έχουν μια από τις δυο βάσεις, δηλαδή να ξεκινά η κάθε διάσταση από το 0 ή από το 1 (μέχρι δέκα διαστάσεις υποστηρίζει η γλώσσα).

Βάση 0 \\ εξ ορισμού είναι 0 - Προσοχή δεν δέχται έκφραση αλλά μόνο το 1 ή το 0
Πίνακας Βάση 1, Α(10), Β() \\ ******* Πίνακας Βάση 1, ... ή Πίνακας Βάση 0, ...νέο στη 16
Πίνακας Β(4,6) \\ θυμάται ότι έχουμε ορίσει βάση 1 για τον πίνακα Β()
Πίνακας Δέλτα(10) \\ αυτός έχει βάση 0
Τύπωσε Διάσταση(Δέλτα()) \\ 1
Τύπωσε Διάσταση(Β()) \\ 2  *******Νεο****** στη 16
Τύπωσε Διάσταση(Β(),0) \\ 1 μας δίνει την βάση
Τύπωσε Διάσταση(Β(), 1) \\ 4 αριθμός στοιχείων στην πρώτη διάσταση
Τύπωσε Διάσταση(Β(), 2) \\ 6 αριθμός στοιχείων στην δεύτερη διάσταση


Δουλεύει και με πίνακες σε ομάδες (Κλάση στη Μ2000 είναι συνάρτηση που γυρίζει ομάδα. Ένα τμήμα με το όνομα της κλάσης είναι ο κατασκευαστής - δεν είναι απαραίτητο να υπάρχει, αλλά μπορούμε να θέλουμε η Κλάση να έχει κατά τη δημιουργία κάποια ρύθμιση. Εδώ γεμίζουμε όλα τα στοιχεία από το 1 μέχρι το τελευταίο με αύξηση κατά 1. Βάζουμε μια τοπική λάμδα να δίνει σε κάθε στοιχείο του πίνακα το νέο αριθμό. Η Κ στη Λάμδα είναι ιδιωτική. Πρώτα φτιάχνεται το αντικείμενο Λάμδα και μετά καταχωρείται στην Ν.

Κλάση Αλφα {
      Πίνακας Βάση 1, Μ()
      Τμήμα Αλφα {
            Πόσα=100
            Διάβασε ? Πόσα
            Ν=Λάμδα Κ=1 ->{=Κ : Κ++}
            Πίνακας .Μ(Πόσα)<<Ν()
      }
}
Ν=Αλφα()
Τύπωσε Ν.Μ(100)=100 \\ -1
Πίνακας Ν.Μ(30) \\ μείωση
Τύπωσε Διάσταση(Ν.Μ(),1) \\ 30
Τύπωσε Διάσταση(Ν.Μ(),0) \\ 1, ξεκινάει από 1
Ν=Αλφα(300)
Τύπωσε Διάσταση(Ν.Μ(),1) \\ 300
Τύπωσε Διάσταση(Ν.Μ(),0) \\ 1, ξεκινάει από 1
Τύπωσε Ν.Μ(300) \\ 300



3) Διόρθωσα ένα μικρό λάθος. Κατά την αντιγραφή ενός αντικειμένου γεγονότος σε ένα εντός ομάδας με το χειριστή (ή τελεστή) <= χανόταν η αντιγραφή, ενώ λειτουργούσε με =. Τώρα λειτουργεί και με <=.Το <= μπήκε για να ξεχωρίζει ο Διερμηνευτής αν φτιάχνουμε μια τοπική ή δίνουμε τιμή σε μια μεταβλητή (ή ιδιότητα) της ομάδας (αντικείμενο της Μ2000).

Ομάδα Κ {
Ιδιωτικό:
      Γεγονός Χ {Διάβασε Τ}
Δημόσιο:
      Τμήμα ΔεςΕδώ {
            \\ Διάβασε .Χ  - εδώ με μια γραμμή, χωρίς το Ν
            Διάβασε Ν
            <=Ν
      }
      Τμήμα ΚάνεΚάτι {
            Κάλεσε Γεγονός, Αριθμός \\ διαβάζει από το σωρό
      }
}
Γεγονός Μ {
      Διάβασε Τ
      Συνάρτηση {
            Τύπωσε Τ
      }
}
Κ.ΚάνεΚάτι 100 \\ δεν κάνει τίποτα γιατί το Χ δεν έχει συνδεθεί με μια συνάρτηση τουλάχιστον
Κ.ΔεςΕδώ Μ
Κ.ΚάνεΚάτι 100

Κυριακή 12 Φεβρουαρίου 2017

Νέο Μικρό Εγχειρίδιο!

Ανέβηκε ανανεωμένο το μικρό εγχειρίδιο της Μ2000. Δείτε δεξιά στις συνδέσεις, όπως και στο τέλος αυτής της ανάρτησης. Προστέθηκαν παραρτήματα, για την εγκατάσταση, μια λίστα με όλα τα αναγνωριστικά καθώς και το πρόγραμμα σε Μ2000 που διαμορφώνει κανείς την βάση δεδομένων για την βοήθεια, το μηχανισμό ενσωματωμένης βοήθειας του περιβάλλοντος Μ2000.
Το αρχείο pdf έχει και το odf ενσωματωμένο για να μπορεί κανείς να διορθώσει και αυτό, με το LibreOffice 5.

Μικρό εγχειρίδιο της Μ2000

Σάββατο 11 Φεβρουαρίου 2017

Γρήγορη Ταξινόμηση σε πίνακα με ρουτίνα

Εδώ έχω μια μικρή εφαρμογή που δείχνει την Γρήγορη ταξινόμηση ως ρουτίνα (και βοηθητικές) στην Μ2000 (οι ρουτίνες έχουν αναδρομή). Είναι σαν εφαρμογή, εμφανίζει τίτλο, αποτελέσματα, περιμένει ένα πλήκτρο και πάει στο επόμενο αποτέλεσμα.
Είναι γραμμένο με δυνατότητες από την 8.2 έκδοση, αν 15, οπότε καλό είναι όποιος έχει κατεβάσει παλαιότερη έκδοση να την αναβαθμίσει. Φαίνεται και η χρήση της λάμδα ως μετρητής, και η χρήση του χειριστή << για αλλαγή κάθε στοιχείου στο πίνακα στην εντολή Πίνακας.

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

Υπάρχουν εντολές ταξινόμησης σε αντικείμενα τύπου Έγγραφο (Document) )και τύπου Κατάσταση (Inventory), αλλά εδώ βλέπουμε την μορφή της με εντολές της Μ2000.
Επειδή οι πίνακες μπορούν να έχουν πίνακες ή άλλα αντικείμενα, η εντολή Άλλαξε (Swap), λειτουργεί στο βάθος, και μεταφέρει 12byte, που μπορεί να έχουν την τιμή και το είδος, ή να έχουν δείκτη σε αντικείμενο. Γενικά η Μ2000 δεν αφήνει να διαβάσουμε δείκτη σε αντικείμενο, ούτε να βάλουμε δική μας τιμή στο δείκτη. Γνωρίζει τι είναι αντικείμενο, επειδή δημιουργεί αντικείμενα και ασχολείται με τους έτοιμους δείκτες όταν φτιάχνουμε νέα αντικείμενα. Εκτός από ειδική περίπτωση (δες Κατάσταση) όλα τα άλλα αντικείμενα έχουν αναλογία ένας δείκτης- ένα αντικείμενο. Οι αναφορές σε αυτά τα αντικείμενα είναι έμμεσος δείκτης στο πραγματικό δείκτη. Στις καταστάσεις μπορούμε να κάνουμε κυκλική αναφορά, δηλαδή να έχει η κατάσταση αναφορά στον εαυτό της, ή χειρότερα, αναφορά σε άλλη όπου η άλλη να έχει αναφορά στην πρώτη. Η Μ2000 έχει τρόπο να βρίσκει αυτές τις κυκλικές αναφορές και να τις καταστρέφει όταν πρέπει!

\\ γρήγορη ταξινόμηση
\\  φτιάχνουμε την οθόνη να δείχνει 40 γραμμές με 60 χαρακτήρες
Φόρμα 60,40
Οθόνη 5 : Πένα 14
\\ με το 2 βάζουμε στο κέντρο της γραμμής την αναφορά μας!


Διπλά  \\ διπλού ύψους και πλάτους γράμματα
Αναφορά 2,"Γρήγορη Ταξινόμηση με χρήση Ρουτινών με Αναδρομή"
Κανονικά
Οθόνη 1,2: Πένα 11 \\ το 2 σημαίνει ότι χωρίζει η οθόνη από την τρίτη γραμμή


\\ Δυο γεννήτριες αριθμών - φτιαγμένες σε συναρτήσεις τύπου λάμδα
\\ αυτές μπορούν να έχουν δικές τους μεταβλητές που δεν σβήνουν μετά την κλήση
\\ αυτό μας βολεύει για να φτιάχνουμε μετρητές.


Counter =Λάμδα x=1 ->{ =x : x++}
CounterRev =Λάμδα x=30 ->{ =x : x--}


\\
\\ φτιάχνουμε δυο πίνακες, και γεμίζουμε τον ένα


Βάση 0 \\ εξ ορισμού είναι 0 αλλά δεν μας πειράζει να το ορίσουμε ξανά


\\ οι πίνακες κρατούν την βάση 0 ή 1 μέχρι να χαθούν.
\\ ο χειριστής << δηλώνει εδώ "εκτέλεσε την συνάρτηση δεξιά για κάθε στοιχείο"


Πίνακας arr(30)<<CounterRev(), old()


\\ αν θέλουμε σκιάζουμε την παρακάτω με \\
\\ η παρακάτω εντολή σημαίνει βάλε από το 0 και πάνω τα στοιχεία μετά το =
\\ άλλαξε το (0) με (10) για να πάβε από το 10 και μετά...
arr(0)=4,2,3,102,23,21,1,54,26,9


\\ αντιγραφή του πίνακα για να μπορούμε να δείξουμε τον παλιό με τον κανούριο
old()=arr()


\\ ξεκινάμε από τη βάση
γρήγορη_ταξινόμηση(&arr(), 0, 29)
Διαμέσου τύπωσε_πίνακα
περίμενε_πλήκτρο()


\\ όλα τα στοιχεία ίδια
Πίνακας arr(30)=1, old() : old()=arr() : γρήγορη_ταξινόμηση(&arr(), 0, 29)
Διαμέσου τύπωσε_πίνακα
περίμενε_πλήκτρο()


\\ ταξινομημένος
Πίνακας arr(30)<<counter(), old() : old()=arr() : γρήγορη_ταξινόμηση(&arr(), 0, 29)
Διαμέσου τύπωσε_πίνακα
περίμενε_πλήκτρο()
\\ κρατάμε αντίγραφο της λάμδα σε μια μεταβλητή ως νέα λάμδα συνάρτηση
counterrev2=counterrev


\\ δοκιμάζουμε σε νέους πίνακες με βάση 1 (από 1 έως 30 αντί από 0 έως 29)
\\ η γρήγορη ταξινόμηση δεν αλλάζει, γιατί δίνουμε πάντα από την αρχή το διάστημα που θα λειτουργήσει


Βάση 1 : Πίνακας arr1(30)<<counterrev(), old1() : old1()=arr1() : Βάση 0 \\ να μη τον ξεχνάμε!
γρήγορη_ταξινόμηση(&arr1(), 1, 30)
Διαμέσου τύπωσε_πίνακα1
περίμενε_πλήκτρο()


Βάση 1 : Πίνακας arr1(30)<<counterrev2()*4, old1()
για i=2 έως 30 ανα 2 : arr1(i)-! : arr1(i)+=4 : επομενο i
old1()=arr1() : Βάση 0 \\ να μη τον ξεχνάμε!
γρήγορη_ταξινόμηση(&arr1(), 1, 30)
Διαμέσου τύπωσε_πίνακα1
περίμενε_πλήκτρο()


Τέλος
τύπωσε_πίνακα:
      \\ Απλή ρουτίνα, δεν έχουμε κάτι να περάσουμε
      \\ ούτε να δημιουργήσουμε τοπικά όπως κάνουμε στις ρουτίνες.
      \\ η Διαμέσου είναι η Gosub. Και οι ρουτίνες μπορούν να κληθούν με Διαμέσου
      \\ και πρέπει αν το όνομα της ρουτίνας είναι ίδιο όνομα πίνακα στο τμήμα.   
      Για i=0 Έως 29
            Τύπωσε μορφη$("{0:-8}={1::4}  {2::-4}",μορφη$("arr({0})", i),arr(i), old(i))
      Επόμενο i
Επιστροφή
τύπωσε_πίνακα1:
      Για i=1 Έως 30
            Τύπωσε μορφη$("{0:-9}={1::4}  {2::-4}",μορφη$("arr1({0})",i), arr1(i), old1(i))
      Επόμενο i
Επιστροφή
Ρουτίνα περίμενε_πλήκτρο()
      Διπλά
      Αναφορά 2, "Πάτησε ένα πλήκτρο"
      Κανονικά
      Τοπική a$=Κομ$
Τέλος Ρουτίνας
\\ τα ονόματα των ρουτινών αν είναι ελληνικά τότε πρέπει να έχουν και την εντολή ρουτίνα με ελληνικά
\\ αν είναι στα αγγλικά πρέπει να έχουν την εντολή Sub και στο τέλος End Sub.
\\ με & σημαίνει με αναφορά. Εδώ το Α() δείχνει ότι το arr()
Ρουτίνα γρήγορη_ταξινόμηση(&A())
      \\ Αυτή χρειάστηκε μόνο για να δημιουργήσει την Α()
      \\ που είναι αναφορά της arr()
      \\ μέχρι το τέλος αυτής της ρουτίνας, θα υπάρχει και αυτή η αναφορά
      \\ τα δυο νούμερα που έχουμε περάσει τα αφήνουμε να τα διαβάσει
      \\ η γρήγορη()
      Αναλυτής
      γρήγορη()
      Οθόνη : Τύπωσε Φόρτος \\ μετράμε τον φόρτο ως  χρόνος εκτέλεσης
Τέλος Ρουτίνας
Ρουτίνα ταξινόμησε(p,r)
      Τοπική x = A(r), i = p-1
      Για j=p Έως r-1
            Αν A(j) <= x Τότε i = i+1 : Άλλαξε A(i),A(j)
      Επόμενο j
      Άλλαξε A(i+1),A(r)
      Βάλε i+1
      \\ οι ρουτίνες είναι μέρη τμήματος, και χειρίζονται τον ίδιο σωρό τιμών\
      \\ έτσι μπορούν να διαβάζουν από αυτόν αλλά και να βάζουν τιμές σε αυτόν
Τέλος Ρουτίνας
Ρουτίνα γρήγορη(p, r)
      Αν p >= r Τότε Έξοδος Ρουτίνας
      ταξινόμησε(p, r) : Διάβασε τοπικά q
      γρήγορη(p, q - 1)
      γρήγορη(q + 1, r)
Τέλος Ρουτίνας



Τέλος εδώ είναι η QuickSort στα αγγλικά και χωρίς τη χρήση ρουτινών. Η κλήση της quicksort γίνεται με την Call Local (Κλήση τοπικά) για να συμβαίνει ότι και με τις υπορουτίνες, να εκτελούνται ως μέρη του τμήματος, άρα να βλέπουν την partition. Διαφορετικά θα έπρεπε να κάνουμε Global την partition (Function Global partition { ... }) και να αφαιρέσουμε το Local στο Call (κλήση). Πιο κάτω είναι η άλλη λύση με τη χρήση αναδρομής σε συνάρτηση ομάδας (Group)

Base 0
\\ Quick Sort using Call Local
Function partition {
         Read &A(), p, r
         x = A(r)
         i = p-1
         For j=p to r-1 {
             If A(j) <= x Then {
                       i = i+1
                    Swap A(i),A(j)
                 }
          }
          Swap A(i+1),A(r)
         = i+1
      }
Function quicksort {
     Read New &A(), p, r
     If p < r Then {
       q = partition(&A(), p, r)
       Call Local quicksort(&A(), p, q - 1)
       Call Local quicksort(&A(), q + 1, r)
    }
}


Dim arr(10), old()
arr(0)=23,21,1,4,2,3,102,54,26,9
old()=arr()
Call Local quicksort(&arr(), 0, 9)
For i=0 to 9
      Print arr(i), old(i)
Next i


Εδώ έχουμε ομάδα (Group) με συναρτήσεις. Οι συναρτήσεις σε μια ομάδα βλέπουν τις άλλες συναρτήσεις της ομάδας (και τυχόν δικές τους), εφόσον ορίζονται στο ίδιο επίπεδο, αλλά και συναρτήσεις άλλων υποομάδων στην ομάδα. Την συνάρτηση partition την έχουμε ιδιωτική (private), δηλαδή δεν μπορεί να κληθεί απ΄έξω!

Base 0
\\ Using a Group
Group Quick {
Private:
      Function partition {
               Read &A(), p, r
               x = A(r)
               i = p-1
               For j=p to r-1 {
                   If A(j) <= x Then {
                             i = i+1
                          Swap A(i),A(j)
                       }
                }
                Swap A(i+1),A(r)
               = i+1
            }
Public:
      Function quicksort {
           Read &A(), p, r
           If p < r Then {
             q = .partition(&A(), p, r)
             Call .quicksort(&A(), p, q - 1)
             Call .quicksort(&A(), q + 1, r)
          }
      }
}
Dim arr(10), old()
arr(0)=23,21,1,4,2,3,102,54,26,9
old()=arr()
Call Quick.quicksort(&arr(), 0, 9)
For i=0 to 9
      Print arr(i), old(i)
Next i

Παρασκευή 10 Φεβρουαρίου 2017

Tutorial for Groups in M2000

To run this code, please copy it in module in M2000 environment, (M2000.exe): Start the environment, type Edit A, copy this program from browser, press Esc to return to CLI (command line interpreter), and type A and press Enter.

Group Abc { X=10, Y, Z$="Yes"}
For This {
      \\ This is a block for temporary definitions
      Group Temp {X=12, W=13}
      \\ we make a copy as "float" group
      \\ float groups are groups in stack and arrays and the result of any function which return group
      \\ non float group, static, is a group with a name, and position in module.
      \\ Group Temp erased after the exit of this block
      Push Temp
}
\\ now reading a group from stack to named (static) group means Join
Read Abc


\\ We see that we get new value for Abc.X, and a new variable Abc.W
For Abc {
      Print .X, .Y, .W, .Z$ \\
}
List   \\ we see all 5 variables group and four group variables


\\ Why is 5? Because in a named group each element exist as it is not in a group.
\\ We can't delete a already defined variable (until module exit) and this happen for groups.
\\ So groups can take more variables and other (Arrays, Functions etc), temporary or not.
\\ We can pass a variable from group by reference without passing the group.
Module CheckRef {
      Read &M
      M++
      Print M \\14
}
\\ by referenece one variable from group Abc
CheckRef &Abc.W
Print Abc.W \\14


\\ We can Add function to group
Group Abc {
      Function CheckIt {
            \ one dot mean This.
            This.X++ \\ change some state
            .Y+=3
            =.X*.W+.Y
      }
}
Print Abc.CheckIt() \\ 185
Print Abc.CheckIt() \\ 202
Print Abc.CheckIt() \\ 219


\\ We can pass a function of Group in a module, and we can change state inside it,
Module PassFunc {
      Read &F()
      Print F() \\ 236
}
PassFunc &Abc.CheckIt()


Module PassAll {
      Read &AbcRef
      \\ now AbcRef is a group
      For AbcRef {
            Print .X, .Y, .W, .Z$
      }
      List  \\ there are 5 more variables
}
PassAll &Abc
\\ Some times is better to pass a weak reference only
\\ this can be done using Weak$() or & operator
\\ but important is what we have in Read


Module WeakPass {
      Read A$
      For A$ {
            Print .X, .Y, .W, .Z$
      }
      \\ we can use A$ to call modules or change variables
      A$.X+=10
      Print Eval(A$.X) \\ we must read using Eval(), or Eval$() for strings
      Print Eval(A$.CheckIt()) \\ 393      
      List  \\ there are NO 5 more variables, only a new string variable (weak reference)
}
WeakPass &Abc
For This {
      \\ temporary use
      Local M, I=Group.Count(Abc)
      For M=1 to I : Print member$(Abc, M), member.type$(Abc, M) : Next M
      \\ we use New so we shadow any variable with same name
      Read New From Abc, X, Y$, Z$, W
      \\ these are references. If not match type (array or variable) we get error
      \\ Here we make string the reference to Y
      Print X, Y$, Z$, W
      Z$="it is a reference to Abc.Z$"
      Y$="1500"
}
List
Print Abc.Z$, Abc.Y \\  "it is a reference to Abc.Z$"   1500


\\ until here____________________________________________

A small program:

\\ We can make reference from number to string variable
A=10
Link A to A$
\\ feed A$ from A
For A=A to A+10 {
      Print A$;
}
Print
\\ feed A from A$
A$="1212.1292"
Print A*100


Advanced Program
M2000 has no interfaces for Groups (Groups are like javascript objects, but not exactly). So here is a program to implement "interface". The task not only needed for give interface to group for particular task, but we need to take feedback, so we must find a way to add functions to groups and from what we get, we need to take something back.
Our feedback is kept in counter in each item (circle or rect). The interface is kept in another group named Geometry. We use a function type$() to define "soft" type. So function interface choose the right group to export. This group then joined to original group

Clear  \\ variables
Flush  \\ Stack for values


Class Circle { Radius, counter
      Function Type$ {="Circle"}
}
Class Rect { Height, Width, counter
      Function Type$ {="Rect" }
}
Group Geometry {
Private:
      Group Geometry_Rect {
            Function Perim { =.Height*2+.width*2}
            Function Area { =.Height*.width}
      }
      Group Geometry_Circle {
            Function Perim { =.Radius*2*pi}
            Function Area { =.Radius**2*pi}
      }
Public:
      Function Interface {
            Read What
            If What.Type$()="Circle" then {
                  =.Geometry_Circle
            } else {
                  =.Geometry_Rect
            }
      }
}
\\ main
Base 1
Dim A(10)=Circle(), B(10)=Rect(), Mix(10)
A(1).Radius=5 \\ we can put .Radious=5 inside For A(1) { }
For A(1) {
      measure(&this, &Geometry.Interface())
}
For B(1) {
      .Width=3 : .Height=4
      measure(&this , &Geometry.Interface())
}
Print A(1).counter, B(1).counter
Mix(1)=A(1)
Mix(2)=B(1)
For Mix(1) {
      measure(&this, &Geometry.Interface())
}
For Mix(2) {
      measure(&this , &Geometry.Interface())
}
Sub measure(&G, &Geometry()) \\ group refer and function (from group) refer
    G=Geometry(G) \\ temporary union with group Geometry
    Print format$("Type     {0:12}", G.Type$())
    Print format$("Area     {0:3:-10}mm",G.Area())
    Print format$("Perimeter{0:3:-10}mm",G.Perim())
    G.counter++ \\ this is feedback
End Sub

___________________________________
And here is another variant of  previous program. Now we don't use a Group Function to return group, but a function. From Sub measure we see everything from module, so we see Function Geometry. More simple now:

Clear  \\ variables - help on developing this
Flush  \\ Empty Stack for values


Class Circle { Radius, counter
      Function Type$ {="Circle"}
}
Class Rect { Height, Width, counter
      Function Type$ {="Rect" }
}
Function Geometry {
            Read What
            If What.Type$()="Circle" then {
                  Group Geometry_Circle {
                        Function Perim { =.Radius*2*pi}
                        Function Area { =.Radius**2*pi}
                  }
                  =.Geometry_Circle
            } else {
                  Group Geometry_Rect {
                        Function Perim { =.Height*2+.width*2}
                        Function Area { =.Height*.width}
                  }
                  =.Geometry_Rect
            }
}
\\ main
Base 1
Dim A(10)=Circle(), B(10)=Rect(), Mix(10)
A(1).Radius=5 \\ we can put .Radious=5 inside For A(1) { }
For A(1) {
      measure(&this)
}
For B(1) {
      .Width=3 : .Height=4
      measure(&this)
}
Print A(1).counter, B(1).counter
Mix(1)=A(1)
Mix(2)=B(1)
For Mix(1) {
      measure(&this)
}
For Mix(2) {
      measure(&this)
}
Sub measure(&G) \\ group refer and function (from group) refer
    \\ sub see anything in module, so can see Geometry()
    G=Geometry(G) \\ temporary union with group Geometry
    Print format$("Type     {0:12}", G.Type$())
    Print format$("Area     {0:3:-10}mm",G.Area())
    Print format$("Perimeter{0:3:-10}mm",G.Perim())
    G.counter++ \\ this is feedback
End Sub



Previous program, with a change. We can pass function G.type$() by reference of each group to Geometry() and not all group, to choose the functions we want to bind to G.
When a function of Group passed by reference we have a new function (a copy of Group's function, with a proper weak reference to Group, so any identifier inside function with a dot precede it, connect by weak reference to actual members of group. All functions and modules in a group have a weak reference to group. When a Group has no name (as those in an array), no weak reference exist. When we open a Group from array item, then interpreter make a new group with a hidden name and make all members using this name, and pass references to this group to modules and functions, and the identifier This refer to this hidden name.
So passing function only, we don't make a copy of group, just a copy of one function.

How reference for Group works

Here we pass a reference of This to sub Measure(), so  interpreter make all members, as identifiers and pointers to actual members of This (we say This but this is an alias, of a copy in of Mix(i)). But G Group has not a pointer to This, has a list of members, as G.identifier_of_member. Calling Geometry() we pass G.type$() which points to This.type$() so we get the weak reference of This. So any bind to G from Geometry, listed only to G and not toThis. So we have two lists, as two objects, with two set of members, but for G some members points to This members, and some aren't references but are new members to G.

From 8.2 we can make the Read Parameter1,...  as  Function Name (Parameter1,...) {function code  }. Interpreter get the parameter list and insert a Read command as first line.
Another change is the For.. to... {} for Mix() array.
Command Modules ? display modules as they are in Modules/Functions List (if not hidden, or private)




Clear  \\ variables - help on developing this
Flush  \\ Empty Stack for values

Class Circle { Radius, counter
      Function Type$ {="Circle"}
}
Class Rect { Height, Width, counter
      Function Type$ {="Rect" }
}
Function Geometry (&What$()) {
            If What$()="Circle" then {
                  Group Geometry_Circle {
                        Function Perim { =.Radius*2*pi}
                        Function Area { =.Radius**2*pi}
                  }
                  =.Geometry_Circle
            } else {
                  Group Geometry_Rect {
                        Function Perim { =.Height*2+.width*2}
                        Function Area { =.Height*.width}
                  }
                  =.Geometry_Rect
            }
}
\\ main
Base 1
Dim A(10)=Circle(), B(10)=Rect(), Mix(10)
A(1).Radius=5 \\ we can put .Radious=5 inside For A(1) { }
For A(1) {
      measure(&this)
}
For B(1) {
      .Width=3 : .Height=4
      measure(&this)
}
Print A(1).counter, B(1).counter
Mix(1)=A(1)
Mix(2)=B(1)
For i=1 to 2 {
      For Mix(i) {
            measure(&this)
      }
}
MM=Mix(1)
Modules ?
Sub measure(&G) \\ group refer and function (from group) refer
    \\ sub see anything in module, so can see Geometry()
    G=Geometry(&G.type$()) \\ temporary union with group Geometry
    Print format$("Type     {0:12}", G.Type$())
    Print format$("Area     {0:3:-10}mm",G.Area())
    Print format$("Perimeter{0:3:-10}mm",G.Perim())
    G.counter++ \\ this is feedback
    
Modules ?
End Sub




Very Advanced

Here we have an Event inside Group.


Group aa {
Private:
      y=123
Public:
      \\ event need a Read parameter list
      \\ so any function added to Event must have same signature
      Event b { Read x, &counter }
      Function aa (x, &counter) {
            Print x+.y
             .y++
            Print ".y=";.y
            counter++
      }
      Module callme {
            Call Event .b, number
      }
}
Class cbb {
Private:
      y=456
Public:
      function bb (x, &cnt) {
            print x**2+.y
            cnt++
      }
Class:
      Module cbb (.y) { }
}
bb=cbb(456)

Event aa.b New aa.aa(), bb.bb()
mycounter=0
aa.callme 10, &mycounter
aa.callme 10, &mycounter
Print mycounter
Module testme (c) {
      Print Module$ \\ name of module
      Stack  \\ display stack (for values not process stack), now have 5 as top value
      \\ a module get parent stack so 5 passed with stack to c.callme module
      c.callme
}
\\ aa by copy
mycounter=0
testme aa, 5, &mycounter
Module testme2 (&c) {
      Print Module$
      c.callme
}
Print  "Calls number=";mycounter
\\  aa by reference
mycounter=0
Event aa.b Drop aa.aa()
testme2 &aa, 10, &mycounter
Print mycounter
Event aa.b Hold
testme2 &aa, 10, &mycounter
Function SomethingElse (x, &cnt) {
      Print ">>>>>>>>>>>",x, cnt
}
Print mycounter
Event aa.b Clear \\ after Clear we need to Release Event
Event aa.b New aa.aa(), aa.aa(), bb.bb(), bb.bb(), SomethingElse()
Event aa.b Drop aa.aa()
Event aa.b Release
mycounter=0
testme2 &aa, 10, &mycounter
Print mycounter