Εμφάνιση αναρτήσεων με ετικέτα Παραδείγματα. Εμφάνιση όλων των αναρτήσεων
Εμφάνιση αναρτήσεων με ετικέτα Παραδείγματα. Εμφάνιση όλων των αναρτήσεων

Κυριακή 15 Μαρτίου 2020

Open a form after closing from unload button

This is an example of how we use a form, here with a handler as SIMPLE, to pass it to three modules, Inner, Inner1 and Inner2. Each module open the form, and when we close it using the unload button on the header of the form we make a fake unload using the Unload event, which handle the visible property to hide the form.

The Inner module get a copy of the window handler. This copy can't be used to make a linked property.

Why that happen ? Is the way M2000 interpreter internal window manager work. Only one real reference to a form exist. This means that when the module CheckIt exit, this reference released, and the form unloaded. The same done when we place a Nothing. When we click on unload button, an unload happen except we cancel it using the true as value to the first by reference variable at unload event. All events called in the same module we make the form and they have the name of the declaration, here the SIMPLE, here the simple.unload function is the service routine for the event. The call is a local type, which means that inside code in function Sumple.Unload we have the visibility of module checkit, so we can see the visible property.

So in Inner module we open the form as modal, using the m2000 internal window manager for modal windows. When we click on unload button, the modal loop exit, but the form not unload, but hide.

When we call the Inner1 we pass the Simple by reference, so we can make a visible property. Now we use a simple loop on visible property to make it like a modal (but a modal type to show also lock the under the form forms).

When we call the Inner2 we pass the Simple and the Visible both by reference.

Although the name of form inside Inner, Inner1 and Inner2 is That, the actual form has the name Simple and a prefix, as a weak reference to use it to call events. Also has a list for those events that aren't servising. This list erased and make it again if the form loose the focus.

If we make a fault in code, the module's stop working and all the variables erased, so the form unload, because the form's handler always is one. The visible property never hold a reference to form, but a reference to where Simple reference, the real reference which is only one.


Module CheckIt {
      \\ Simple is a first class object
      Declare Simple Form
      \\ we can define form before open
      Layer Simple {
            \\ center Window with 12pt font, 12000 twips width and 6000 twips height
            \\ ; at the end command to center the form in current screen
            Window 12, 12000, 6000;
            \\ make layer gray and split screen 0
            Cls #333333, 0
            \\   set split screen to 3rd line, like Cls ,2 without clear screen
            Scroll Split 2
            Cursor 0, 2
      }
      With Simple, "Title", "Hello Form", "visible" as visible
      \\ Without handling the unload event, a form unload for good
      \\ So we have to cancel the unload event and make the form non visible
      Function Simple.Unload {
            Read New &cancel
            visible=False
            cancel=true
      }
      Function Simple.Click {
            Layer Simple {
                  \\ open msgbox
                  Print Ask("Hello World")
                  Refresh
            }
      }
      Module Inner (That) {
            \\ open as modal  - also we handle the Unload event
            Method That, "Show", 1
      }
      Module Inner1 (&That) {
            \\ we can produce a linked property if we pass by reference
            \\ so &That make That same as Simple
            \\ if we pass by value we get an error "Can't Get Property"
            With That, "visible" as visible
            Method That, "Show"
            do
                  wait 1
            until not visible
      }
      Module Inner2 (&That, &thatToo) {
            Method That, "Show"
            do
                  wait 1
            until not thatToo
      }
      Inner Simple
      wait 1000
      Print "ok"

      Refresh
      Inner1 &Simple
      wait 1000
      Print "ok"

      Refresh
      Inner2 &Simple, &visible
      \\ now form deleted
      \\ Make the Simple as Nothing the form unloaded if not unloaded,
      \\ without an unload event.
      Declare Simple Nothing
}
CheckIt

Κυριακή 8 Μαρτίου 2020

Δένδρο του Πυθαγόρα (Αναδρομή)

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

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

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

Για την εμφάνιση του δένδρου χρησιμοποιούμε δυο εντολές, την Θέση που δέχεται απόλυτη τιμή καρτεσιανών συντεταγμένων (η πάνω αριστερή γωνία είναι το 0,0 και το ύψος αυξάνει προς τα κάτω οπότε η κάτω δεξιά γωνία είναι η χ.σημεία-πλάτος.σημείου, υ.σημεία-ύψος.σημείου). Οι μονάδες είναι τα twips, και ένα pixel έχει πλάτος όσο το πλάτος.σημείου και ύψος όσο το ύψος.σημείου. Τα 1440 twips είναι μια λογική ίντσα στην οθόνη και μια κανονική στο χαρτί του εκτυπωτή. Η λογική ίντσα λέγεται έτσι γιατί ένα μόνιτορ μπορεί να αλλάζει το πραγματικό μήκος της, αλλά και η θέση μας από αυτήν αλλάζει το μέγεθος επίσης.

Το πρόγραμμα ρυθμίζει τα χρώματα φόντου και γραμμών/κειμένου, σε Ματζέντα και Κίτρινο.
Μπορούμε να δώσουμε html χρώματα όπου το #FF0000 είναι το κόκκινο, η με την Χρώμα(255, 0,0).

Επίσης ενεργοποιεί την χάραξη γραμμών με anti-aliasing μια διαδικασία που είναι αργότερη από την απλή χάραξη αλλά ομαλοποιεί τα σκαλοπάτια που δημιουργούν οι πλάγιες γραμμές.

Η Στη ή Let εδώ μπήκε για ομορφιά! Αν δεν την βάζαμε θα έπρεπε μεταξύ δυο εκχωρήσεων να βάλουμε την αλλαγή εντολής την άνω και κάτω τελεία και όχι το κόμμα.

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


ΤΜΗΜΑ Δένδρο_Πυθαγόρα {
 ΟΘΟΝΗ 5, 0  ' ΜΑΤΖΕΝΤΑ, ΧΩΡΙΣ ΧΩΡΙΣΤΗ ΟΘΟΝΗ
 ΠΕΝΑ 14   ' ΚΙΤΡΙΝΟ
 ΟΜΑΛΑ ΝΑΙ  ' χρήση GDI+ για ομαλοποίηση στις γραμμές
 
 ΣΤΗ π =Χ.ΣΗΜΕΙΑ , υ = π * 11 ΔΙΑ 16
 ΣΤΗ π2 = π ΔΙΑ 2, διαφορά = π ΔΙΑ 12
 ΣΤΗ ΤάξηΔένδρου = 6
 Δένδρο_Πυθαγόρα(π2 - διαφορά, υ-10, π2 + διαφορά, υ-10, 0)
 
 ΡΟΥΤΙΝΑ Δένδρο_Πυθαγόρα(χ1, ψ1, χ2, ψ2, βάθος)
 
     ΑΝ βάθος > ΤάξηΔένδρου ΤΟΤΕ ΕΞΟΔΟΣ ΡΟΥΤΙΝΑΣ
 
     ΤΟΠΙΚΗ δχ = χ2 - χ1, δψ = ψ1 - ψ2
     ΤΟΠΙΚΗ χ3 = χ2 - δψ, ψ3 = ψ2 - δχ
     ΤΟΠΙΚΗ χ4 = χ1 - δψ, ψ4 = ψ1 - δχ
     ΤΟΠΙΚΗ χ5 = χ4 + (δχ - δψ) / 2
     ΤΟΠΙΚΗ ψ5 = ψ4 - (δχ + δψ) / 2
     ΘΕΣΗ χ1, ψ1
     ΧΑΡΑΞΕ ΕΩΣ χ2, ψ2
     ΧΑΡΑΞΕ ΕΩΣ χ3, ψ3
     ΧΑΡΑΞΕ ΕΩΣ χ4, ψ4
     ΧΑΡΑΞΕ ΕΩΣ χ1, ψ1
     Δένδρο_Πυθαγόρα(χ4, ψ4, χ5, ψ5, βάθος+1)
     Δένδρο_Πυθαγόρα(χ5, ψ5, χ3, ψ3, βάθος+1)
 
 ΤΕΛΟΣ ΡΟΥΤΙΝΑΣ
}
Δένδρο_Πυθαγόρα


Παραλλαγή του προγράμματος με χρήση τμήματος αντί για ρουτίνα.
Τα τμήματα είναι πιο βαριές κατασκευές από τις ρουτίνες.

Για να καλέσουμε ένα τμήμα πρέπει να έχει δοθεί από πριν ο ορισμός του. Επίσης για να καλέσουμε ένα τμήμα με αναδρομή πρέπει να χρησιμοποιήσουμε τη ΚΑΛΕΣΕ,

Εδώ έχουμε το εσωτερικό τμήμα με το ίδιο όνομα με το εξωτερικό. Η πρώτη κλήση καλεί το εσωτερικό και η δεύτερη επειδή είναι με την ΚΑΛΕΣΕ καλεί το τρέχον.

Δείτε τις αλλαγές:
1. Το έξοδος δεν έχει τη λέξη ΡΟΥΤΙΝΑΣ
2. Οι μεταβλητές που θέλουμε να διαβάζονται σε κάθε κλήση αναδρομής πρέπει να είναι γενικές, γιατί εντός τμήματος θέαση υπάρχει μόνο για τοπικές του τμήματος και γενικές.

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


Οι κλήσεις τμημάτων περιορίζονται σε βάθος σε μερικές χιλιάδες. Σε αντίθεση η κλήση ρουτινών μπορεί να είναι σε βάθος σε εκατοντάδες χιλιάδες.

ΤΜΗΜΑ Δένδρο_Πυθαγόρα {
 ΟΘΟΝΗ 5, 0  ' ΜΑΤΖΕΝΤΑ, ΧΩΡΙΣ ΧΩΡΙΣΤΗ ΟΘΟΝΗ
 ΠΕΝΑ 14   ' ΚΙΤΡΙΝΟ
 ΟΜΑΛΑ ΝΑΙ  ' χρήση GDI+ για ομαλοποίηση στις γραμμές
 
 ΓΕΝΙΚΕΣ π =Χ.ΣΗΜΕΙΑ , υ = π * 11 ΔΙΑ 16
 ΓΕΝΙΚΕΣ π2 = π ΔΙΑ 2, διαφορά = π ΔΙΑ 12
 ΓΕΝΙΚΕΣ ΤάξηΔένδρου = 6
 ΤΜΗΜΑ Δένδρο_Πυθαγόρα(χ1, ψ1, χ2, ψ2, βάθος) {
 
     ΑΝ βάθος > ΤάξηΔένδρου ΤΟΤΕ ΕΞΟΔΟΣ
 
     ΣΤΗ δχ = χ2 - χ1, δψ = ψ1 - ψ2
     ΣΤΗ χ3 = χ2 - δψ, ψ3 = ψ2 - δχ
     ΣΤΗ χ4 = χ1 - δψ, ψ4 = ψ1 - δχ
     ΣΤΗ χ5 = χ4 + (δχ - δψ) / 2
     ΣΤΗ ψ5 = ψ4 - (δχ + δψ) / 2
     ΘΕΣΗ χ1, ψ1
     ΧΑΡΑΞΕ ΕΩΣ χ2, ψ2
     ΧΑΡΑΞΕ ΕΩΣ χ3, ψ3
     ΧΑΡΑΞΕ ΕΩΣ χ4, ψ4
     ΧΑΡΑΞΕ ΕΩΣ χ1, ψ1
     ΚΑΛΕΣΕ Δένδρο_Πυθαγόρα χ4, ψ4, χ5, ψ5, βάθος+1
     ΚΑΛΕΣΕ Δένδρο_Πυθαγόρα χ5, ψ5, χ3, ψ3, βάθος+1
 }
 Δένδρο_Πυθαγόρα π2 - διαφορά, υ-10, π2 + διαφορά, υ-10, 0
}
Δένδρο_Πυθαγόρα







Στο Info αρχείο που υπάρχει στην εγκατάσταση της γλώσσας υπάρχει το Pyth με αγγλικές εντολές το πρώτο πρόγραμμα καθώς και το Pyth1 επίσης με αγγλικές εντολές με εμφάνιση δυο δένδρων υπό γωνία το ένα αντικριστό από το άλλο:

Pyth1:

MODULE Pythagoras_Example{
 CLS 5, 0  ' MAGENTA, split line = 0  
 PEN 14  ' YELLOW
 \\ Linux smoothing not work (we can use the statement but without effect)
 IF ISWINE ELSE SMOOTH ON
 \\ PYTHAGORAS TREE
 \\ by definition all variables ar type of a double
 GLOBAL p=7, p4=PI/4, p2=PI/2, s2=SQRT(2)/2
 MODULE center_p (r, t){
  MODULE pythagoras_tree (r, dx, depth) {
   r2=r-p2
   DRAW ANGLE r, dx
   DRAW ANGLE r2, dx
   DRAW ANGLE r, -dx
   DRAW ANGLE r2, -dx
   IF depth>10 THEN EXIT
   s3=dx*s2
   depth++
   STEP ANGLE r+p4, s3*2
   CALL pythagoras_tree r-p4,  s3, depth
   STEP ANGLE r, -dx-s3
   STEP ANGLE r, s3
   STEP ANGLE r+p4, -s3
   CALL pythagoras_tree r+p4,  s3, depth
   STEP ANGLE r-p4, s3  
  } 
  MOVE SCALE.X/2, SCALE.Y/2 
  STEP ANGLE PI-p4+r, t*s2
  CALL pythagoras_tree r, t, 1
 }
 r=PI/3
 pixels=100
 center_p r, 100*TWIPSX
 center_p r+PI, 100*TWIPSX
 CopyImageToClipboard()
 
 Sub CopyImageToClipboard()
  LOCAL Scr$=""
  MOVE 0,0
  COPY SCALE.X, SCALE.Y TO Scr$
  CLIPBOARD Scr$
 END SUB
}
Pythagoras_Example



Σάββατο 9 Ιουνίου 2018

Ουρά με δείκτες (Queue with pointers)

Το πρόγραμμα γράφτηκε αρχικά με αγγλικές εντολές και μετά έγινε μετατροπή με ελληνικές. Όμως διατηρήθηκαν τα ονόματα των αναγνωριστικών με λατινικούς χαρακτήρες. (Προστέθηκε και ο κώδικας με όλα τα αναγνωριστικά στα ελληνικά).
Το πρόγραμμα δείχνει πως φτιάχνουμε μια δυναμική λίστα τύπου ουράς, όπου έχουμε πρόσβαση πάντα σε μια κορυφή, και μπορούμε να την πετάξουμε, μέχρι να αδειάσει η ουρά, ή μπορούμε να κόψουμε την ουρά σε δυο, μια την αρχική και μια δεύτερη, ή να ενώσουμε μια ουρά σε μια άλλη (στο τέλος της).
Δεν χρησιμοποιούμε πίνακες. Κάθε στοιχείο της ουράς είναι μια ομάδα που έχει ένα δείκτη σε μια άλλη ομάδα ή είναι μηδενικός. Αυτό που χρησιμοποιούμε για ασφάλεια είναι το μήκος της ουράς που υπάρχει σε κάθε στοιχείο, και δεν χρειάζεται να γνωρίζουμε αν έχουμε ή όχι μηδενικό δείκτη, αφού μας το λέει άμεσα το "μήκος", πχ αν το μήκος είναι 1 τότε δεν έχουμε "συνέχεια" μέσα από τον δείκτη για ομάδα.
Εδώ να επισημάνω ότι ο τελεστής -> δίνει ένα δείκτη σε μια ομάδα, αλλα'επειδή έχουμε δυο ειδών δείκτες, έναν που αντιστοιχεί σε επώνυμες ομάδες, και έναν άλλο που αντιστοιχεί σε ανώνυμες ομάδες, εδώ μας ενδιαφέρει το δεύτερο και για το λόγο αυτό μετά το -> η ομάδα που μας ενδιαφέρει να πάρουμε ένα δείκτη γίνεται ανώνυμη με παρενθέσεις () (ουσιαστικά αντίγραφο της επώνυμης, ως κλειστή ομάδα- και πάλι το κλειστή ομάδα είναι ορολογία της Μ2000 και δηλώνει την ανώνυμη ομάδα όπου τα μέλη της είναι κλειστά, και δεν μπορούν να χρησιμοποιηθούν). Μια κλειστή ομάδα χρησιμοποιείται αφού την ανοίξει ο διερμηνευτής, που σημαίνει να την "τοποθετήσει" σε θέαση, στο συγκεκριμένο σημείο του κώδικα που θέλουμε να διαβάσουμε ή να αλλάξουμε σε αυτήν κάτι.
Ως βελτίωση για το πρόγραμμα, μπαινει η άσκηση στο πώς να βγάλουμε εκτός τις αναδρομικές κλήσεις, στις μεθόδους SliceQueue και MergeQueue.
Στο τέλος ακολουθεί η αγγλική έκδοση των εντολών της Μ2000.

Παρατηρηση: Οι μεταβλητές στη Μ2000 γράφονται σε μια λίστα που η εύρεσή τους γίνεται πολύ γρήγορα (με πίνακα κατακερματοσμού). Ο βασικός διερμηνευτής δεν κατανοεί τα αντικείμενα, βλέπει κάθε στοιχείο του αντικειμένου ξεχωριστά. Σε αυτή τη περίπτωση το αντικείμενο είναι ανοικτό. Το κλειστό αντικείμενο είναι σαν μια ξεχωριστή αποθήκη τιμών χωρίς άμεση πρόσβαση από τον βασικό διερμηνευτή. Πχ η τιμή Q=>length για να αποδοθεί πρέπει ο δείκτης Q να δώσει ένα  όνομα,  πχ a123 το οποίο  θα ενωθεί με το length ως a123.length. Το a123 είναι το ανοικτό αντικείμενο, όπου μπορεί ο βασικός διερμηνευτής να βρει το a123.length ως όνομα μεταβλητής (όπου η τελεία είναι ένας χαρακτήρας του ονόματος μόνο). Υπάρχει διαφορά πως εμείς καταλαβαίνουμε τα αντικείμενα και πως τα ορίζει και τα χειρίζεται ο διερμηνευτής).

\\ Η γενική κλάση QueueClass
\\ δίνει ό,τι χρειάζεται για να προσθέτουμε στη κορυφή
\\ να πετάμε από την κορυφή
\\ να  μετακινούμε από ένα σημείο και κάτω της ουράς σε μια νέα ουρά
\\ να προσθέτουμε στο τέλος μιας ουράς μια άλλη ουρά
\\ σε κάθε περίπτωση η ουρά δίνει άμεσα το μέγεθός της
\\ Για κάθε στοιχείο της ουράς υπάρχει το NextClass ως δείκτης του επόμενου στοιχείου
\\ όπως και το length, ως το μήκος (ο αριθμός στοιχείων) από το σημείο αυτό και κάτω
\\ Η κλάση Queue δεν ασχολείται με το τι μεταφέρει το κάθε στοιχείο
\\ Όταν φτιάχνουμε ένα στοιχείο της φροντίζουμε να περνάμε μια άλλη κλάση που δίνει
\\ ένα αντικείμενο όπως το θέλουμε, με τα στοιχεία που θέλουμε (εδώ το λέμε items)
\\ αλλά και με ένα τμήμα ResetClass όπου το καλεί η QueueClass για να καθαρίσει τα στοιχεία,
\\ αυτού που φέρει ως απαίτηση όταν η ουρά είναι άδεια.
\\ Η ουρά ξεκινάει με ένα τουλάχιστον στοιχείο. Αλλά μπορεί να αδειάσει, είτε γιατί την κόψαμε από το πρώτο στοιχείο
\\ είτε γιατί την αδειάσαμε με συνεχόμενα την DropTop, είτε γιατί περάσαμε όλα τα στοιχεία της στην ουρά μιας άλλης ουράς!

Κλάση QueueClass {
      Ομάδα NextClass
      Ιδιότητα Length {Αξία}=1
      Τμήμα NewTop (nTop) {
                  nTop.NextClass->(Αυτό)
                  old=.[Length]+1
                  Αυτό=Ntop
                  .[Length]<=old
            }
      Τμήμα ClearAll {
            .[length]<=0
            Δες {.ResetClass}
            .NextClass->0&
      }
      Τμήμα MergeQueue (&Q1 ) {
                  Αν .[Length]=0 Τότε {
                        Αυτό=Q1
                  } Αλλιώς {
                        Q2->(Q1)
                        Κάλεσε Κενή .MoveDeep(.[Length], Q2)
                  }
                 Q1.ClearAll
      }
      Συνάρτηση MoveDeep (level, Q) {
                    Αν level>1 Τότε {
                         m->.Nextclass
                         .[length]+=m=>MoveDeep(level-1, Q)
                  } Αλλιώς {
                        .NextClass->Q
                         .[length]+=Q=>Length
                         =Q=>Length
                  }
            }
      Συνάρτηση SliceQueue (level) {
              Αν level>.[Length] Τότε {
                    Λάθος "Can't Slice"
            } Αλλιώς {
                  Z=.SliceQueueDeep(Level)
                  =Ομάδα(Z)
            }
      }
      Συνάρτηση SliceQueueDeep (level) {
              Αν level>1 Τότε {
                   m->.Nextclass
                   z=m=>SliceQueueDeep(level-1)
                   ->(z)
                   .[length]-=z=>length
            } Αλλιώς {
                  ->(Αυτό)
                  .NextClass->0&
                   .[length]<=0
                   Δες { .ResetClass }
            }
      }
      Τμήμα DropTop {
                 Αν .[Length]>0 Τότε {
                       old=.[Length]-1
                       Δες {
                              Αυτό=Ομάδα(.NextClass)
                        }
                        .[Length]<=old
                        Αν .[Length]==0 Τότε {
                             Δες { .ResetClass }
                        }
                  }  Αλλιώς Λάθος "Nothing to Drop"
            }
Κλάση:
     \\ οτιδήποτε μετά τξμ ετικέτα Κλάση:  δεν θα  υπάρχει στη τελική ομάδα
     \\ εδώ έχουμε το τμήμα που καλούμε κατά την κατασκευή της ομαας
      Τμήμα QueueClass (extend) {
            .NextClass->0&
            Αυτό=extend
      }
}

\\ Έχουμε άλλη μια κλάση που θα τη δώσουμε στην παραπάνω κλάση
\\Η Items δεν γνωρίζει που θα μπει, αλλά παρέχει μια ResetClass
\\ για να δημιουργεί  την κενή ομάδα τύπου items
Κλάση Items {
\\ X and Y are read only properties
      Ιδιότητα X {Αξία}=0
      Ιδιότητα Y {Αξία}=0
      Τμήμα ResetClass {
            .[X]<=0
            .[Y]<=0
      }     
Κλάση:
      Τμήμα Items (.[X], .[Y]) {}
}
\\ Τώρα φτιάχνουμε μια ομάδα  QueueClass μαζί με μια Items
\\ αυτός είναι ο απλός τρόπος να συχγωνεύσουμε δυο αντικείμενα
M=QueueClass(items(10, 20))
Τύπωσε M.X, M.Y ' 10, 20
\\ Τώρα αλλάζουμε το Μ βάζοντας στη κορυφή το νέο και από κάτω
\\ στην ουρά ότι υπήρχε
M.NewTop QueueClass(Items(15, 25))
Τύπωσε "New Item"
Τύπωσε M.X, M.Y ' 15, 25
\\ μπορούμε να δούμε τι υπάρχει ακριβώς στο προηγούμενο
\\ με χρήση του δείκτη NextClass
Τύπωσε M.NextClass=>X, M.NextClass=>Y ' 10, 20
\\ Βάζουμε και τρίτο Items, πάλι με επέκταση QueueClass
M.NewTop QueueClass(Items(50, 100))
Τύπωσε "New Item"
\\ Και πάλι κοιτάμε τα στοιχεία στη κορυφή και αμέσως μετά
Τύπωσε M.X, M.Y ' 50,100
Τύπωσε M.NextClass=>X, M.NextClass=>Y ' 15, 25
Τύπωσε "M.NextClass Length";M.NextClass=>Length
Τύπωσε "M length=";M.Length
\\ Τώρα θα φτιάξουμε ένα κομμάτι της Μ ως Ζ και θα ορίσουμε από ποιο σημείο θα κόψουμε
\\ μπορούμε από το 1 ή το 2 ή το 2
\\ εδώ κόβουμε από το 2 άρα το 1 θα μείναι στο Μ
Z=M.SliceQueue(2)
Τύπωσε "M Length="; M.Length, "Top Item X="; M.X
Τύπωσε "Z Length="; Z.Length, "Top Item X="; Z.X
\\ εδώ μπορούμε να επιλέξουμε αν θέλουμε να μεταφέρουμε τα στοιχεία του Μ
\\ στο τέλος του Ζ  και να αδειάσοιυμε εντελώς το Μ
Σημ 1 :
Z.MergeQueue &M
\\ ή να κάνουμε το ανάποδο, να επιλέξουμε  να μεταφέρουμε τα στοιχεία του Ζ
\\ στο Μ και να αδειάσουμε το Ζ
Σημ 2 : M.MergeQueue &Z
Τύπωσε "M Length="; M.Length, "Top Item X="; M.X
Τύπωσε "Z Length="; Z.Length, "Top Item X="; Z.X
\\ Ότι και να κάνουμε θα αδειάσουμε και το Μ και το Ζ
Δες {
      Τύπωσε "Drop Item M"
      Τύπωσε M.X, M.Y
      M.DropTop
      Τύπωσε "M length=";M.Length
      Κυκλικά
}
Δες {
      Τύπωσε "Drop Item Z"
      Τύπωσε Z.X, Z.Y
      Z.DropTop
      Τύπωσε "Z length=";Z.Length
      Κυκλικά
}


Εδώ όλα στα ελληνικά και οι μεταβλητές:


\\ Η γενική κλάση ΜιαΟυρά
\\ δίνει ό,τι χρειάζεται για να προσθέτουμε στη κορυφή
\\ να πετάμε από την κορυφή
\\ να  μετακινούμε από ένα σημείο και κάτω της ουράς σε μια νέα ουρά
\\ να προσθέτουμε στο τέλος μιας ουράς μια άλλη ουρά
\\ σε κάθε περίπτωση η ουρά δίνει άμεσα το μέγεθός της
\\ Για κάθε στοιχείο της ουράς υπάρχει το ΕπόμενηΟμάδα ως δείκτης του επόμενου στοιχείου
\\ όπως και το ΜήκοςΟυράς, ως το μήκος (ο αριθμός στοιχείων) από το σημείο αυτό και κάτω
\\ Η κλάση ΜιαΟυρά δεν ασχολείται με το τι μεταφέρει το κάθε στοιχείο
\\ Όταν φτιάχνουμε ένα στοιχείο της φροντίζουμε να περνάμε μια άλλη κλάση που δίνει
\\ ένα αντικείμενο όπως το θέλουμε, με τα στοιχεία που θέλουμε (εδώ το λέμε Περιεχόμενο)
\\ αλλά και με ένα τμήμα ΚαθάρισεΟμάδα όπου το καλεί η ΜιαΟυρά για να καθαρίσει τα στοιχεία,
\\ αυτού που φέρει ως απαίτηση όταν η ουρά είναι άδεια.
\\ Η ουρά ξεκινάει με ένα τουλάχιστον στοιχείο. Αλλά μπορεί να αδειάσει, είτε γιατί την κόψαμε από το πρώτο στοιχείο
\\ είτε γιατί την αδειάσαμε με συνεχόμενα την ΠέταΚορυφή, είτε γιατί περάσαμε όλα τα στοιχεία της στην ουρά μιας άλλης ουράς!

Κλάση ΜιαΟυρά {
      Ομάδα ΕπόμενηΟμάδα
      Ιδιότητα ΜήκοςΟυράς {Αξία}=1
      Τμήμα ΝέαΚορυφή (Κορυφή) {
                  Κορυφή.ΕπόμενηΟμάδα->(Αυτό)
                  παλιό=.[ΜήκοςΟυράς]+1
                  Αυτό=Κορυφή
                  .[ΜήκοςΟυράς]<=παλιό
            }
      Τμήμα ΚαθάρισεΌλα {
            .[ΜήκοςΟυράς]<=0
            Δες {.ΚαθάρισεΟμάδα}
            .ΕπόμενηΟμάδα->0&
      }
      Τμήμα ΈνωσεΟυρά (&κ1 ) {
                  Αν .[ΜήκοςΟυράς]=0 Τότε {
                        Αυτό=κ1
                  } Αλλιώς {
                        κ2->(κ1)
                        Κάλεσε Κενή .ΣτοΒάθος(.[ΜήκοςΟυράς], κ2)
                  }
                 κ1.ΚαθάρισεΌλα
      }
      Συνάρτηση ΣτοΒάθος (Βάθος, κ) {
                    Αν Βάθος>1 Τότε {
                         μ->.ΕπόμενηΟμάδα
                         .[ΜήκοςΟυράς]+=μ=>ΣτοΒάθος(Βάθος-1, κ)
                  } Αλλιώς {
                        .ΕπόμενηΟμάδα->κ
                         .[ΜήκοςΟυράς]+=κ=>ΜήκοςΟυράς
                         =κ=>ΜήκοςΟυράς
                  }
            }
      Συνάρτηση ΚόψεΟυρά (Βάθος) {
              Αν Βάθος>.[ΜήκοςΟυράς] Τότε {
                    Λάθος "Δεν μπορώ να κόψω"
            } Αλλιώς {
                  Ζ=.ΚόψεΟυράΒάθος(Βάθος)
                  =Ομάδα(Ζ)
            }
      }
      Συνάρτηση ΚόψεΟυράΒάθος (Βάθος) {
              Αν Βάθος>1 Τότε {
                   μ->.ΕπόμενηΟμάδα
                   ζ=μ=>ΚόψεΟυράΒάθος(Βάθος-1)
                   ->(ζ)
                   .[ΜήκοςΟυράς]-=ζ=>ΜήκοςΟυράς
            } Αλλιώς {
                  ->(Αυτό)
                  .ΕπόμενηΟμάδα->0&
                   .[ΜήκοςΟυράς]<=0
                   Δες { .ΚαθάρισεΟμάδα }
            }
      }
      Τμήμα ΠέταΚορυφή {
                 Αν .[ΜήκοςΟυράς]>0 Τότε {
                       παλιό=.[ΜήκοςΟυράς]-1
                       Δες {
                              Αυτό=Ομάδα(.ΕπόμενηΟμάδα)
                        }
                        .[ΜήκοςΟυράς]<=παλιό
                        Αν .[ΜήκοςΟυράς]==0 Τότε {
                             Δες { .ΚαθάρισεΟμάδα }
                        }
                  }  Αλλιώς Λάθος "Τίποτα για να πετάξω"
            }
Κλάση:
     \\ οτιδήποτε μετά την ετικέτα Κλάση:  δεν θα  υπάρχει στη τελική ομάδα
     \\ εδώ έχουμε το τμήμα που καλούμε κατά την κατασκευή της ομαας
      Τμήμα ΜιαΟυρά (επέκταση) {
            .ΕπόμενηΟμάδα->0&
            Αυτό=επέκταση
      }
}

\\ Έχουμε άλλη μια κλάση που θα τη δώσουμε στην παραπάνω κλάση
\\ ΟΙ κλάσεις είναι συναρτήσεις που επιστρέφουν Ομάδες.
\\Η Περιεχόμενο δεν γνωρίζει που θα μπει, αλλά παρέχει μια ΚαθάρισεΟμάδα
\\ για να δημιουργεί  την κενή ομάδα τύπου Περιεχόμενο
Κλάση Περιεχόμενο {
\\ οι Χ και Υ είναι ιδιότητες μόνο για ανάγνωση
\\ εσωτερικά γράφονται στις .[Χ] και .[Υ] που είναι ιδιωτικές στην ομάδα.
      Ιδιότητα Χ {Αξία}=0
      Ιδιότητα Υ {Αξία}=0
      Τμήμα ΚαθάρισεΟμάδα {
            .[Χ]<=0
            .[Υ]<=0
      }     
Κλάση:
      Τμήμα Περιεχόμενο (.[Χ], .[Υ]) {}
}
\\ Τώρα φτιάχνουμε μια ομάδα  ΜιαΟυρά μαζί με μια Περιεχόμενο
\\ αυτός είναι ο απλός τρόπος να συχγωνεύσουμε δυο αντικείμενα
Μ=ΜιαΟυρά(Περιεχόμενο(10, 20))
Τύπωσε Μ.Χ, Μ.Υ ' 10, 20
\\ Τώρα αλλάζουμε το Μ βάζοντας στη κορυφή το νέο και από κάτω
\\ στην ουρά ότι υπήρχε
Μ.ΝέαΚορυφή ΜιαΟυρά(Περιεχόμενο(15, 25))
Τύπωσε "Νέο Περιεχόμενο"
Τύπωσε Μ.Χ, Μ.Υ ' 15, 25
\\ μπορούμε να δούμε τι υπάρχει ακριβώς στο προηγούμενο
\\ με χρήση του δείκτη NextClass
Τύπωσε Μ.ΕπόμενηΟμάδα=>Χ, Μ.ΕπόμενηΟμάδα=>Υ ' 10, 20
\\ Βάζουμε και τρίτο Περιεχόμενο, πάλι με επέκταση ΜιαΟυρά
Μ.ΝέαΚορυφή ΜιαΟυρά(Περιεχόμενο(50, 100))
Τύπωσε "Νέο Περιεχόμενο"
\\ Και πάλι κοιτάμε τα στοιχεία στη κορυφή και αμέσως μετά
Τύπωσε Μ.Χ, Μ.Υ ' 50,100
Τύπωσε Μ.ΕπόμενηΟμάδα=>Χ, Μ.ΕπόμενηΟμάδα=>Υ ' 15, 25
Τύπωσε "Μ.ΕπόμενηΟμάδα ΜήκοςΟυράς";Μ.ΕπόμενηΟμάδα=>ΜήκοςΟυράς
Τύπωσε "Μ ΜήκοςΟυράς=";Μ.ΜήκοςΟυράς
\\ Τώρα θα φτιάξουμε ένα κομμάτι της Μ ως Ζ και θα ορίσουμε από ποιο σημείο θα κόψουμε
\\ μπορούμε από το 1 ή το 2 ή το 2
\\ εδώ κόβουμε από το 2 άρα το 1 θα μείναι στο Μ
Ζ=Μ.ΚόψεΟυρά(2)
Τύπωσε "Μ ΜήκοςΟυράς="; Μ.ΜήκοςΟυράς, "Περιεχόμενο Κορυφής Χ="; Μ.Χ
Τύπωσε "Ζ ΜήκοςΟυράς="; Ζ.ΜήκοςΟυράς, "Περιεχόμενο Κορυφής Χ="; Ζ.Χ
\\ εδώ μπορούμε να επιλέξουμε αν θέλουμε να μεταφέρουμε τα στοιχεία του Μ
\\ στο τέλος του Ζ  και να αδειάσοιυμε εντελώς το Μ
Σημ 1 :
Ζ.ΈνωσεΟυρά &Μ
\\ ή να κάνουμε το ανάποδο, να επιλέξουμε  να μεταφέρουμε τα στοιχεία του Ζ
\\ στο Μ και να αδειάσουμε το Ζ
Σημ 2 : Μ.ΈνωσεΟυρά &Ζ
Τύπωσε "Μ ΜήκοςΟυράς="; Μ.ΜήκοςΟυράς, "Περιεχόμενο Κορυφής Χ="; Μ.Χ
Τύπωσε "Ζ ΜήκοςΟυράς="; Ζ.ΜήκοςΟυράς, "Περιεχόμενο Κορυφής Χ="; Ζ.Χ
\\ Ότι και να κάνουμε θα αδειάσουμε και το Μ και το Ζ
Δες {
      Τύπωσε "Πέτα Στοιχείο στο Μ"
      Τύπωσε Μ.Χ, Μ.Υ
      Μ.ΠέταΚορυφή
      Τύπωσε "Μ ΜήκοςΟυράς=";Μ.ΜήκοςΟυράς
      Κυκλικά
}
Δες {
      Τύπωσε "Πέτα Στοιχείο στο Ζ"
      Τύπωσε Ζ.Χ, Ζ.Υ
      Ζ.ΠέταΚορυφή
      Τύπωσε "Ζ ΜήκοςΟυράς=";Ζ.ΜήκοςΟυράς
      Κυκλικά
}








Και η αγγλική έκδοση:

\\ this is a generic class for Queue
Class QueueClass {
      Group NextClass
      Property Length {value}=1
      Module NewTop (nTop) {
                  nTop.NextClass->(This)
                  old=.[Length]+1
                  This=Ntop
                  .[Length]<=old
            }
      Module ClearAll {
            .[length]<=0
            Try {.ResetClass}
            .NextClass->0&
      }
      Module MergeQueue (&Q1 ) {
                  if .[Length]=0 then {
                        This=Q1
                  } else {
                        Q2->(Q1)
                        call void .MoveDeep(.[Length], Q2)
                  }
                 Q1.ClearAll
      }
      Function MoveDeep (level, Q) {
                    if level>1 then {
                         m->.Nextclass
                         .[length]+=m=>MoveDeep(level-1, Q)
                  } else {
                        .NextClass->Q
                         .[length]+=Q=>Length
                         =Q=>Length
                  }
            }
      Function SliceQueue (level) {
              if level>.[Length] then {
                    Error "Can't Slice"
            } else {
                  Z=.SliceQueueDeep(Level)
                  =Group(Z)
            }
      }
      Function SliceQueueDeep (level) {
              if level>1 then {
                   m->.Nextclass
                   z=m=>SliceQueueDeep(level-1)
                   ->(z)
                   .[length]-=z=>length
            } else {
                  ->(this)
                  .NextClass->0&
                   .[length]<=0
                   Try { .ResetClass }
            }
      }
      Module DropTop {
                 If .[Length]>0 then {
                       old=.[Length]-1
                       Try {
                              This=Group(.NextClass)
                        }
                        .[Length]<=old
                        if .[Length]==0 then {
                             Try { .ResetClass }
                        }
                  }  Else Error "Nothing to Drop"
            }
Class:
     \\ anything after Class: are not  included to final list of group members
      Module QueueClass (extend) {
            .NextClass->0&
            This=extend
      }
}

\\ This is the items class which feed the QueueClass
\\ we have to use a ResetClass if we want to make an empty Items class
Class Items {
\\ X and Y are read only properties
      Property X {value}=0
      Property Y {value}=0
      Module ResetClass {
            .[X]<=0
            .[Y]<=0
      }     
Class:
      Module Items (.[X], .[Y]) {}
}
M=QueueClass(items(10, 20))
Print M.X, M.Y ' 10, 20
M.NewTop QueueClass(Items(15, 25))
Print "New Item"
Print M.X, M.Y ' 15, 25

Print M.NextClass=>X, M.NextClass=>Y ' 10, 20
M.NewTop QueueClass(Items(50, 100))
Print "New Item"
Print M.X, M.Y ' 50,100
Print M.NextClass=>X, M.NextClass=>Y ' 15, 25
Print "M.NextClass Length";M.NextClass=>Length
Print "M length=";M.Length

Def CopyPointer(X)=Group(X)
\\ WE CAN SLICE THE QUEUE TO 1 OR 2 OR 3 ITEM
Z=M.SliceQueue(2)
Print "M Length="; M.Length, "Top Item X="; M.X
Print "Z Length="; Z.Length, "Top Item X="; Z.X
Rem 1 :
Z.MergeQueue &M
Rem 2 : M.MergeQueue &Z
Print "M Length="; M.Length, "Top Item X="; M.X
Print "Z Length="; Z.Length, "Top Item X="; Z.X
Try {
      Print "Drop Item M"
      Print M.X, M.Y
      M.DropTop
      Print "M length=";M.Length
      loop
}
Try {
      Print "Drop Item Z"
      Print Z.X, Z.Y
      Z.DropTop
      Print "Z length=";Z.Length
      loop
}