Πέμπτη 30 Αυγούστου 2018

Αναθεώρηση 13, Έκδοση 9.4

Επιτέλους σε αυτήν την αναθεώρηση βρήκα τρόπο να παίρνω τον "απαριθμητή" ενός αντικειμένου που φορτώνουμε στη γλώσσα, όπως θα δούμε στα παραδείγματα παρακάτω. Επίσης προστέθηκε και το αντικείμενο Collection της Vb6. Το αντικείμενο Inventory έχει φτιαχτεί για να αντικαταστήσει το Collection,  αλλά τώρα μπήκε περισσότερο για να δούμε τη χρήση  του Enumeratror. (απαριθμητή)


declare fs "Scripting.FileSystemObject"
Method fs, "GetFolder", dir$ as fc
With fc, "files" set files
\\ Produce the TypeLib
mm=param(files)
IF LEN(mm)>1 THEN {
      For i=0 to len(mm)-1
            Report 3, mm$(i!) ' use index, not key
      Next i
}
With files, "count" as count
With files, "item" set myfile ("llist1.gsb")
\\ this is a property -4 which return a IEnumVariant
With files, -4& as EnumFile
Print Type$(EnumFile)
\\ Produce the TypeLib
m=param(EnumFile)
IF LEN(m)>1 THEN {
      For i=0 to len(m)-1
            Report 3, m$(i!) ' use index, not key
      Next i
}
With EnumFile, "Name" as aName$
While EnumFile {
      Print aName$
}
declare fs nothing

:Άλλο ένα που δείχνει φακέλους:
declare fs "Scripting.FileSystemObject"
Method fs, "GetFolder", dir$ as fc
With fc, "SubFolders" set SubFolders
Print type$(SubFolders)
With SubFolders, -4& as Folder
With Folder, "Name" as FolderName$
While Folder {
      Print FolderName$
}

declare fs nothing




Εδώ  κατά την χρηση του Collection,





declare c collection
Print type$(c)
m=param(c)
IF LEN(m)>1 THEN {
For i=0 to len(m)-1
Report 3, m$(i!) ' use index, not key
Next i
}

Method c, "Add", 100, "Hello"
Method c, "Add", 2000, "There"
Method c, "Add", 3000032131231231312312@, "Zero"
Method c, "count" as count
Print count
Method C, "_NewEnum" as Item
Method c, "Item", "Zero" as ZeroItem
Print ZeroItem
Print type$(Item)="Nothing"  ' we have numbers
k=0
While Item {
      k++
      print k, eval(item)
}





declare c collection
Print type$(c)
m=param(c)
IF LEN(m)>1 THEN {
For i=0 to len(m)-1
Report 3, m$(i!) ' use index, not key
Next i
}

Method c, "Add", "100", "Hello"
Method c, "Add", "2000", "There"
Method c, "Add", "30000", "Zero"
Method c, "count" as count
Method c, "Item", "Zero" as ZeroItem$
Print ZeroItem$
Print count
Method C, "_NewEnum" as Item

Print type$(Item)
k=0
While Item {
      k++
      print k, eval$(item)
}





Τρίτη 28 Αυγούστου 2018

Game 2048

First publish in Rosettacode.org




Module Game2048 {
      \\ 10% 4 and 90% 2
      Def GetTlleNumber()=If(Random(10)<2->4, 2)
      \\ tile
      Def Tile$(x)=If$(x=0->"[    ]", format$("[{0::-4}]", x))
      \\ empty board
      BoardTileRight =lambda (x, y)->x+y*4
      BoardTileLeft=lambda (x, y)->3-x+y*4
      BoardTileUp=lambda (x, y)->x*4+y
      BoardTileDown=lambda (x, y)->(3-x)*4+y
      Dim Board(0 to 15)
      Inventory EmptyTiles
      \\ Score is a statement but we can use it as a variable too.
      Score=0
      \\ Win is also a statement but we can use it as a variable too.
      Win=False
      ExitNow=False
      BoardDirection=BoardtileRight
      Process(BoardDirection)
      \\ Split Rem lines to insert start condition to check valid moves
      Rem : board(0)=2
      Rem : board(1)=2, 2, 2 ' place to (1), (2), (3)
            While len(EmptyTiles) {
            NewTile()
            DrawBoard()
            Action=False
            do {
                  a$=key$
                  if len(a$)=2 then {
                        Action=true
                        Select case Asc(mid$(a$,2))
                        Case 72
                        BoardDirection=BoardTileUp
                        Case 75
                        BoardDirection=BoardTileRight
                        Case 77
                        BoardDirection=BoardTileLeft
                        Case 80
                        BoardDirection=BoardTileDown
                        Case 79 ' End key
                              ExitNow=True
                        Else
                        Action=false
                        end select
                  }
            } until Action
            If ExitNow then exit
            Process(BoardDirection)
      }
      If Win then {
            Print "You Win"
      } Else {
            Print "You Loose"
      }
      End
      Sub Process(Boardtile)
      Inventory EmptyTiles ' clear inventory
      local where, i, j, k
      For i=0 to 3
            Gravity()
            k=boardtile(0,i)
            For j=1 to 3
                  where=boardtile(j,i)
                  if Board(where)<>0 then {
                        if board(k)=board(where) then {
                               board(k)*=2 : score+=board(where): board(where)=0
                               if board(k)=2048 Then Win=True : ExitNow=true
                        }
                  }
                  k=where
            Next j
            Gravity()
            For j=0 to 3
                  where=boardtile(j,i)
                  if board(where)=0 then Append EmptyTiles, where
            Next j
      Next i
      End Sub
      Sub NewTile()
            local m=EmptyTiles(Random(0, len(EmptyTiles)-1)!)
            Board(m)=GetTlleNumber()
            Delete EmptyTiles, m
      End Sub
      Sub DrawBoard()
            Refresh 2000
            Cls
            Cursor 0, 10
            Local Doc$, line$
            Document Doc$
            Doc$=Format$("Game 2048 Score {0}", score)
            \\ Using Report 2 we use rendering as text, with center justify
            Report 2, Doc$
            Doc$={
            }
            Local i, j
            For i=0 to 3
                  line$=""
                  For j=0 to 3
                        line$+=Tile$(Board(BoardTileRight(j, i)))
                  Next j
                  Print Over $(2), Line$
                  Print
                  Doc$=Line$+{
                  }
            Next i
            Report 2, "Next:Use Arrows | Exit: Press End"
            Refresh
            ClipBoard Doc$
      End Sub
      Sub Gravity()
            k=-1
            for j=0 to 3 {
                  where=boardtile(j,i)
                  if k=-1 then if board(where)=0 then k=j : continue
                  if board(where)=0 then continue
                  if k=-1 then continue
                  board(boardtile(k,i))=board(where)
                  board(where)=0
                  k++
            }  
      End Sub
}
Game2048

Αναθεώρηση 12 Έκδοση 9.4

Με την χρήση του διερμηνευτή στα νέα Ubuntu (18.04) και με χρήση του WINE 3.6,  είδα ότι χρειάζονταν μερικές διορθώσεις, και έτσι έγιναν!
Γενικά είναι δύσκολο να πρέπει ένα πρόγραμμα όπως το περιβάλλον Μ2000, να τρέχει σε διαφορετικά λειτουργικά. Τρέχει σε ubuntu (Ακόμα ελέγχω τη συμβατότητα, πχ ο ήχος από το σύστημα που παίζει νότες δεν ακούγεται, ενώ το πρόγραμμα παίζει κανονικά, και από ότι διάβασα απλά δεν κάνει τίποτα το wine, επειδή δεν έχει φορτωμένους ήχους οργάνων), και τρέχει κανονικά σε όλες τις εκδόσεις από Xp μέχρι και 10 των Windows.





Δευτέρα 27 Αυγούστου 2018

Revision 11 (version 9.4)

Revision 10 work better in Wine 3+, when we use test statement to test a module. I found that without a sleep statement (in VB6 code) wine (in Ubuntu 18.04) hold thread active with very less time than usual to OS (but in Windows, there is a pass to system for waiting objects from message queue, and there is no such a slow down to os performance). The workaround was to insert a sleep 1 statement (which that happen when we choose slow, but now happen when environment run in Wine). We can use IsWine to get true if environment run in Wine (Linux). This function has a static variable so except first call, all other return the stored value.

Also a bug in User statement remove (Revision 11). This bug was an error throwing from a routine which open "desktop.inf", a text file which include some statements to run before show the user console, and happen when no desktop.inf found. So now the error cleared.

Send any message to fotodigitallab  (at gmail.com) with any suggestion. Write title: "For M2000"
 

Τετάρτη 22 Αυγούστου 2018

Αναθεώρηση 7 Έκδοση 9.4

1.Διορθώθηκε ένα Bug στις λάμδα συναρτήσεις σε σχέση με κλείσιμο δείκτη σε ομάδα.
Στο πρόγραμμα που ακολουθεί η next_fact  έχει την fix ως δείκτης σε ομάδα. Αυτή η ομάδα έχει  μια λάμδα την f. Αρχικά αυτή η f  δίνει το 1. Αφού φτιάξουμε την next_fact, πάμε στην fix=>f  και βάζουμε την next_fact, ως αντίγραφο. Τώρα ζητάμε το 5 παραγοντικό, και αυτό βγαίνει χωρίς αναδρομή, απλά με εκτέλεση του αντιγράφου που είναι στην fix.

Class fixme {
      f=lambda->1
}
fix->fixme()
next_fact=lambda fix (x)->{
     if x<=1 then =1 :exit
     =x*fix=>f(x-1)
}
fix=>f=next_fact
Print next_fact(5)
m=next_fact
Print m(5)


Δεν χρειάζεται να κάνουμε τόσα πολύπλοκα πράγματα, γιατί οι λάμδα έχουν αναδρομή με την χρήση της λάμδα() ή λάμδα$() και στα αγγλικά με τις Lambda() και Lambda$(), οι οποίες καλούν την λάμδα, με οποιοδήποτε όνομα και είναι συνδεδεμένες.

2. Μπορούμε από αυτή την αναθεώρηση να εκτελέσουμε μια λάμδα άμεσα, χωρίς να την  δώσουμε σε ένα αναγνωριστικό, βάζοντας παρενθέσεις με τιμές αμέσως μετά τις αγκύλες του σώματος της λάμδα. Επειδή οι λάμδα μπορούν να γραφτούν χωρίς σώμα, αλλά απευθείας με έκφραση, πχ λαμδα (χ)->χ**2  δεν πάει το () (δεν ξέρει ο διερμηνευτής για που πάει, για την έκφραση ή για τη λάμδα;).. Οπότε την γράφουμε έτσι Τύπωσε λαμδα (χ)->{=χ**2}(3)  και θα τυπώσει το 9. Δείτε ότι βάλαμε τις αγκύλες και ένα '=.

Module Ycombinator {
      \\ factorial
      Print lambda (g, x)->{=g(g, x)}(lambda (g, n)->if(n=0->1, n*g(g, n-1)),10)
       \\ fibonacci
      Print lambda (g, x)->{=g(g, x)}(lambda (g, n)->if(n<=1->n,g(g, n-1)+g(g, n-2)), 10)

      \\ Using closure in y, y() return function
      y=lambda (g)->lambda g (x) -> g(g, x)
   
      fact=y((lambda (g, n)-> if(n=0->1, n*g(g, n-1))))
      Print fact(6), fact(24)
   
      fib=y(lambda (g, n)->if(n<=1->n,g(g, n-1)+g(g, n-2)))
      Print fib(10)
}
Ycombinator



λειτουργεί και με την λάμδα για αλφαριθμητικά:
m$=lambda$ (a)->{
      =lambda$ (n)-> {
            =string$("x", n)
      }(a)
}(3)
Print m$





Και ένα ωραίο παράδειγμα με γεγονότα. Η ομάδα Άλφα έχει μια συνάρτηση για να παράγει την ακολουθία fibonacci. Παράλληλα καλεί γεγονότα. Αν έχουμε συνδέσει την ομάδα με συναρτήσεις εξυπηρέτησης γεγονότων (εδώ έχουμε) θα έχουμε ενημέρωση των συναρτήσεων και αυτές εδώ κρατάνε "απογραφή" τα ήδη υπολογισμένα στοιχεία της ακολουθίας, στην Κατάσταση Getit.
Απλά η ομάδα δεν γνωρίζει πώς κρατάμε τα στοιχεία. Απλά ζητάει ένα στοιχείο, ενώ το έχει γράψει ως -1, και αν δει ότι άλλαξε τότε το δέχεται ως σωστό και το επιστρέφει άμεσα. Επίσης κάθε νούμερο που έχει υπολογισθεί, δίνεται για οποιαδήποτε χρήση (εδώ απλά το σώνουμε για να το βρίσκει άμεσα ο αλγόριθμος). Η αναζήτηση σε Κατάσταση γίνεται σε χρόνο O(1)


fixed inversion 9.7 revision 10 (for 9.6 we have to use .fib() instead of lambda())


Module CheckEvents {
      \\ we can use standard functions (not lambda functions)
      \\ we can use lambda() so we can use function with different names
      \\ We can define functions inside groups with events
     Group WithEvents Alfa {
           Event "GetIt", "PushIt"
           Function fib(n) {
                  if n<=1 then {
                        =val(n->Decimal)
                  } else {
                        if n<140 then { m=-1@} else m=-1
                        call event "Getit", n, &m
                        if m>-1 then =m : exit
                        \\ m1 may get double if a decimal can write the result
                        \\ if we use m we get overflow error
                        m1=lambda(n-1)+lambda(n-2)
                        call event "Pushit", n, m1
                        =m1
                  }            
            }
      }
      \\ we use an Inventory list to save old values
      Inventory Getit
      \\ event's service functions
      \\ if not event's functions exist, call event skipped
      Function Alfa_Getit {
            Read new key, &m
            if exist(Getit, key) then m=eval(Getit)
      }      
      Function Alfa_Pushit {
            Read new key, m
            Append Getit, key:=m
      }
      Module Inner (&fibonacci()){
            acc=0
            For i=1 to 200 ' until 139 we get decimal type, above it we get double
                  Print fibonacci(i),
            Next i
      }
      Inner &Alfa.fib()
}
CheckEvents





Κυριακή 19 Αυγούστου 2018

Αναθεώρηση 6 Έκδοση 9.4

Ένα μικρό λάθος διορθώθηκε, το οποίο απέτρεπε την σωστή αντιγραφή ενός δείκτη σε ομάδα σε μια νέα θέση στο σωρό τιμών.

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

Ένας δείκτης σε ομάδα δείχνει σε μια επώνυμη ή σε μια επιπλέουσα ή είναι μηδενικός (παραμένει όμως να έχει τύπο Ομάδα). Αν ο δείκτης δείχνει σε επώνυμη ομάδα στην ουσία έχει ισχνή αναφορά σε αυτήν. Με συνέπεια αν μετακινηθεί ο δείκτης σε χώρο όπου έχει πια διαγραφεί αυτό που δείχνει να έχει άκυρη ισχνή αναφορά, και η οποία θα φανεί με το πρώτη ζήτηση. Αν ο δείκτης δείχνει σε επιπλέουσα ομάδα τότε την κρατάει "ζωντανή", γιατί υπάρχει αρίθμηση στο πόσοι δείκτες την έχουν, και για να διαλυθεί πρέπει να φύγει και ο τελευταίος. Οι δείκτες αντιγράφονται με = ενώ για να πάρουν νέο δείκτη από μια ομάδα πρέπει να δώσουμε αυτό Α->Α(3) όπου σημαίνει ότι ο Α έχει δείκτη σε επιπλέουσα ομάδα (δεν είναι επώνυμη), ή Α->(Αλφα)  όπου οι παρενθέσεις στο όνομα κάνουν το Αλφα να αντιγραφεί σε επιπλέουσα ομάδα, και το Α->Αλφα το οποίο είναι δείκτης σε επώνυμη ομάδα.


Module Big {
      Module Checkit {
            Group Alfa {
                  \\ all are public by default
                  x=-10, y=30, a$="a String"
                  Module testMe {
                        Print .x, .y, .a$
                  }
            }
            \\ show list  Alfa[Group], Alfa.x, Alfa.y, Alfa.a$
            List
            \\ Show Alfa.testMe
            Modules ?
            Alfa.testme
            Dim a(1 to 3)
            A(1)=Alfa
            \\ A(1) has a float group, a copy of Alfa
            A(1).x+=20
            Print A(1).x=10 ' true
            Print Alfa.x=-10 ' true
           
            \\ thin arrow used instead = to get pointer from a group
            \\ notice that A(2)->(Alfa) make a copy before return a pointer
            A(2)->Alfa
            \\ A(2) has a pointer to Alfa (a pointer to a named group is a weak reference, not adding ref count to Alfa)
            \\ we can use this pointer until this module exit, and Alfa erased
            A(2).x+=20
            Print A(2).x=10 ' true
            Print Alfa.x=-10 ' false, it is 10, A(2) has a pointer  to Alfa
            Group Alfa {
                  Function AddXY {
                        =.x+.y
                  }
            }
            Print A(2).AddXY()=40
            \\ A(1) has no AddXY() function
            Print Valid(A(1)..AddXY())=false
            \\ z is a pointer to A(1)
            \\ a pointer to a float group is actual a pointer to object, adding a ref count.
            \\ we can use this pointer anytime because hold object alive
            \\ using z->0& we pass a null, and release the object. This happen at the exit of this module
            \\ but before the exit maybe we tranfer a copy to another destination, like a container, or in current stack of values
            z->A(1)
            Module CallByRef (&a) {
                  a+=1000
            }
            For A(1), A(2), alfa {
                  \\ any new in this block destroyed at exit
                  \\ A(2) points to Alfa, and Alfa exist as named group
                  \\ So only A(1) close all
                  Print .x, ..x, ..x ' 10 10 10
                  ..x+=30
                  Print ..x=40, ...x=40 ' A(2) points to alfa
                  \\ we pass .x (from A(1)) as reference, because .x has a name (hidden), it is linked now
                  CallByRef &.x
                  \\ z points to a float group A(1), but now  A(1 )is linked and so z find link and get proper value
                  \\ we use fat arrow to access member from a pointer (as a variable)
                  \\ for arrays not need to use fat arrow
                  Print z=>x = 1010
            }
            \\ so now we want to upgrade A(1)
            For A(1) {
                   m=Alfa ' we get a copy
                   m=This ' we get a merge
                  This=M ' we get a merge in reverse
            }
            \\ Now M not exist.
            Print A(1).AddXY()
            Push z
       }
      Flush ' empty stack here       
       \\ call checkit
       Checkit
       \\ Print stack items from current stack
       Stack
       \\ we see a  *[Group] means a pointer to Group
       \\ we want Here to read Good as a group (not as a pointer)
       pGroup=StackItem()
       Read Good as group
       \\ Good is a pointer
       Print Good.AddXY() , pGroup=>AddXY()
       pGroup->0& ' release object
       List
       Modules ?
}
Big
\\ There are no variables
List
\\ There is one module Big
Modules ?




Επιπλέον μπήκαν νέες σελίδες στην βοήθεια για τελεστές. Υπάρχει η σελίδα Τελεστές, με βοήθεια τελεστές βγαίνει, αλλά τώρα προστέθηκαν και ξεχωριστές σελίδες για τους τελεστές, στη λίστα ΔΙΕΡΜΗΝΕΥΤΗΣ
Η ΚΑΙ ΑΠΟ ΕΙΝΑΙ ΔΙΑ ΔΙΑ# ΥΠΟΛ ΥΠΟΛ#

Βοήθεια Διερμηνευτής

ή μπορούμε να δώσουμε χωριστά
βοήθεια υπολ
βοήθεια "υπολ#"   (θέλει εισαγωγικά για το #

πχ στο Δια# υπάρχει το παράδειγμα

α=-20
β=6
\\ Ευκλείδεια διαίρεση και υπόλοιπο
γ=α Διά# β
δ=α Υπόλ# β
Τύπωσε γ, δ  ' -4   4
Τύπωσε α=β*γ+δ
\\ Κανονική διαίρεση και υπόλοιπο
γ=α Διά β
δ=α Υπόλ β
Τύπωσε γ, δ ' -3  -2
Τύπωσε α=β*γ+δ

και στα αγγλικά αυτό:
a=-20
b=6
\\ Euclidean  div as div#, mod as mod#
c=a div# b
d=a mod# b
Print c, d  ' -4   4
Print a=b*c+d
\\ normal
c=a div b
d=a mod b
Print c, d ' -3  -2
Print a=b*c+d

Σάββατο 18 Αυγούστου 2018

Αναθεώρηση 5 κδοση 9.4

Σε αυτή την αναθεώρηση έγιναν δυο αναβαθμίσεις

1. Συναρτήσεις για την χρήση Τεραδόνιων (Quaternions).
Είχα δώσει σε πρόγραμμα σε Μ2000 το τεραδόνιο, με αγγλικές εντολές στο RosettaCode.org
Σε αυτήν την αναβάθμιση έβαλα τις συναρτήσεις μέσα στη βιβλιοθήκη Math της M2000. Η διαφορά με τα παρακάτω προγράμματα είναι ότι η βιβλιοθήκη δουλεύει με δείκτες σε διαρθρώσεις μνήμης. Έτσι μπορούμε να έχουμε "μνήμες" με πίνακες από τεραδόνια και να εκτελούμε μαζικούς υπολογισμούς, απευθείας με ρουτίνες σε γλώσσα μηχανής. Βεβαίως και αυτά εδώ τα προγράμματα δεν χάνουν την αξία τους, γιατί έχουμε περισσότερη επαφή με το τι γίνεται και πώς. (αν και ο κώδικας της Μ2000 και της βιβλιοθήκης, που είναι ενσωματωμένη στο περιβάλλον, είναι σε Visual Basic, ωστόσο είναι για προχωρημένους προγραμματιστές πάνω στην γλώσσα VB6).


Τμήμα Δοκίμασε {
      Κλάση Τεραδόνιο {

            α,β,γ,δ
            Ιδιότητα Τιμή$ {
                  Αξία {
                      Ένωσε γονικό α,β,γ,δ στη α,β,γ,δ
                       Αξία$=Μορφή$("{0} + {1}i + {2}j + {3}k",α,β,γ,δ)
                  }
            }
            Ιδιότητα Μέγεθος { Αξία}
            Τελεστής "==" {
                  Διάβασε ν
                  Βάλε ==ν.α και ==ν.β και ==ν.γ και ==ν.δ
            }
            Τμήμα ΥπολόγισεΜ {
                  .[Μέγεθος]<=ρίζα(**2+**2+**2+**2)
             }
            Τελεστής Μοναδιαίος {  ' είναι το - πριν το αντικείμενο
                  -! : -! : -! :-!
            }
            Συνάρτηση Συζ {
                  τ=Αυτό
                  Για τ {
                         -! : -! :-!
                  }
                  =τ
            }
            Συνάρτηση Πρόσθεσε {
                  τ=Αυτό
                  Για τ {
                         +=Αριθμός : .ΥπολόγισεΜ
                  }
                  =τ
            }
            Τελεστής "+"  {
                  Διάβασε τ2
                  Για Αυτό, τ2 {
                        +=..α :+=..β:+=..γ:+=..δ
                        .ΥπολόγισεΜ
                  }
            }
            Συνάρτηση Πολλαπλασίασε(r) {
                  τ=Αυτό
                  Για τ {
                        *=r:*=r:*=r:*=r:.ΥπολόγισεΜ
                  }
                  =τ
            }
            Τελεστής "*" {
                  Διάβασε τ2
                  Για Αυτό, τ2 {
                        Βάλε *..α-*..β-*..γ-*..δ
                        Βάλε *..β+*..α+*..δ-*..γ
                        Βάλε *..γ-*..δ+*..α+*..β
                        <=*..δ+*..γ-*..β+*..α
                        Διάβασε , ,
                        .ΥπολόγισεΜ
                  }
            }      
            Κλάση:
            Τμήμα Τεραδόνιο {
                  Άν Ταύτιση("NNNN") Τότε {
                        Διάβασε ,,,
                       .ΥπολόγισεΜ
                  }
            }
      }

      r=7
      τ=Τεραδόνιο(1,2,3,4)
      τ1=Τεραδόνιο(2,3,4,5)
      τ2=Τεραδόνιο(3,4,5,6)

 
      τ_αρνητικό=-τ
      τ_συζυγή=τ.συζ()
      τ_πολλαπλάσιο=τ.πολλαπλασίασε(r)
      τ_επαυξημένο=τ.Πρόσθεσε(r)
      τ1τ2=τ1*τ2
      τ2τ1=τ2*τ1

      Τύπωσε "τ = ";τ.Τιμή$
      Τύπωσε "Μέγεθος τ = ";τ.Μέγεθος
      Τύπωσε "Αρνητικό τ = ";τ_αρνητικό.Τιμή$
      Τύπωσε "Συζυγή τ = ";τ_συζυγή.Τιμή$
      Τύπωσε "Πολλαπλασίασε τ 7 = ";τ_πολλαπλάσιο.Τιμή$
      Τύπωσε "Πρόσθεσε τ 7 = ";τ_επαυξημένο.Τιμή$
      Τύπωσε "τ1 = ";τ1.Τιμή$
      Τύπωσε "τ2 = ";τ2.Τιμή$
      Τύπωσε "τ1 * τ2 = ";τ1τ2.Τιμή$
      Τύπωσε "τ2 * τ1 = ";τ2τ1.Τιμή$
      Τύπωσε τ1==τ1 ' Αληθής
      Τύπωσε τ1τ2==τ2τ1 ' Ψευδής

      Τύπωσε (τ1 * τ2 == τ2 * τ1)=Ψευδής
      Τύπωσε (τ1 * τ2 == τ1 * τ2)=Αληθής
}
Δοκίμασε

και με αγγλικές εντολές:


Module CheckIt {
      class Quaternion {
            \\ by default are double
            a,b,c,d
            Property ToString$ {
                  Value {
                      link parent a,b,c, d to a,b,c,d
                       value$=format$("{0} + {1}i + {2}j + {3}k",a,b,c,d)
                  }
            }
            Property Norm { Value}
            Operator "==" {
                  read n
                  push .a==n.a and .b==n.b and .c==n.c and .d==n.d
            }
            Module CalcNorm {
                  .[Norm]<=sqrt(.a**2+.b**2+.c**2+.d**2)
             }
            Operator Unary {
                  .a-! : .b-! : .c-! :.d-!
            }
            Function Conj {
                  q=this
                  for q {
                         .b-! : .c-! :.d-!
                  }
                  =q
            }
            Function Add {
                  q=this
                  for q {
                         .a+=Number : .CalcNorm
                  }
                  =q
            }
            Operator "+"  {
                  Read q2
                  For this, q2 {
                        .a+=..a :.b+=..b:.c+=..c:.d+=..d
                        .CalcNorm
                  }
            }
            Function Mul(r) {
                  q=this
                  for q {
                        .a*=r:.b*=r:.c*=r:.d*=r:.CalcNorm
                  }
                  =q
            }
            Operator "*" {
                  Read q2
                  For This, q2 {
                        Push .a*..a-.b*..b-.c*..c-.d*..d
                        Push .a*..b+.b*..a+.c*..d-.d*..c
                        Push .a*..c-.b*..d+.c*..a+.d*..b
                        .d<=.a*..d+.b*..c-.c*..b+.d*..a
                        Read .c, .b, .a
                        .CalcNorm
                  }
            }      
            class:
            module Quaternion {
                  if match("NNNN") then {
                        Read .a,.b,.c,.d
                       .CalcNorm
                  }
            }
      }
      \\ variables
      r=7
      q=Quaternion(1,2,3,4)
      q1=Quaternion(2,3,4,5)
      q2=Quaternion(3,4,5,6)

      \\ perform negate, conjugate, multiply by real, add a real, multiply quanterions, multiply in reverse order
      qneg=-q
      qconj=q.conj()
      qmul=q.Mul(r)
      qadd=q.Add(r)
      q1q2=q1*q2
      q2q1=q2*q1

      Print "q = ";q.ToString$
      Print "Normal q = ";q.Norm
      Print "Neg q = ";qneg.ToString$
      Print "Conj q = ";qconj.ToString$
      Print "Mul q 7 = ";qmul.ToString$
      Print "Add q 7 = ";qadd.ToString$
      Print "q1 = ";q1.ToString$
      Print "q2 = ";q2.ToString$
      Print "q1 * q2 = ";q1q2.ToString$
      Print "q2 * q1 = ";q2q1.ToString$
      Print q1==q1 ' true
      Print q1q2==q2q1 ' false
      \\ multiplication and equality in one expression
      Print (q1 * q2 == q2 * q1)=false
      Print (q1 * q2 == q1 * q2)=True
}
CheckIt


Output:
q = 1 + 2i + 3j + 4k
Normal q = 5.47722557505166
Neg q = -1 + -2i + -3j + -4k
Conj q = 1 + -2i + -3j + -4k            
Mul q 7 = 7 + 14i + 21j + 28k
Add q 7 = 8 + 2i + 3j + 4k
q1 = 2 + 3i + 4j + 5k
q2 = 3 + 4i + 5j + 6k
q1 * q2 = -56 + 16i + 24j + 26k
q2 * q1 = -56 + 18i + 20j + 28k
     True
    False
     True
     True



Παράδειγμα με τη χρήση των νέων συναρτήσεων της βιβλιοθήκης Math.
Επειδή η βιβλιοθήκη χρησιμοποιεί δείκτες πρέπει να δίνουμε δείκτες που εξάγουμε από κάποια Διάρθρωση μνήμης και όχι οτιδήποτε γιατί θα τερματίσει απότομα το περιβάλλον (κρασαρισμα). Γενικά οι διαρθρώσεις έχουν φτιαχτεί για να μην γίνεται αυτό, όμως η βιβλιοθήκη δεν ελέγχει τους δείκτες, και τους χρησιμοποιεί για μετακινήσεις στοιχείων. Αν δεν μπορεί να γράψει, ή αν δεν υπάρχει η διεύθυνση που δίνει ο δείκτης, τότε έχουμε "παραβίαση" άρα άμεσο σταμάτημα.
Αφού ορίσουμε το Math ως αντικείμενο Math, και αφού φτιάξουμε χώρο στη μνήμη για τα τεραδόνια, και ορίσουμε δείκτες στην μνήμη, καλούμε μεθόδους.
Ορισμένες μέθοδοι δέχονται προαιρετικά ορίσματα, και συνήθως είναι το τελευταίο. Πχ αν θέλουμε να προσθέσουμε δυο τεραδόνια, δίνουμε δυο δείκτες, το δείκτη του πρώτου και το δείκτη του δεύτερου, ή τρεις, δηλαδή επιπλέον τον δείκτη που θα πάει το αποτέλεσμα. Αν δεν δώσουμε ειδικά που θέλουμε το αποτέλεσμα θα πάει στο πρώτο.

Ορισμένες μέθοδοι έχουν στο όνομα το Mul (όχι το Mult) το οποίο δηλώνει ότι το πρώτο νούμερο θα είναι ένας αριθμος επαναλήψεων. Ουσιαστικά στους δείκτες που δίνουμε προσθέτει σε κάθε επανάληψη το μέγεθος του στοιχείου που δηλώνει ο δείκτης σε ψηφία μνήμης (bytes). Άρα πρέπει να δώσουμε τόσο όσο θα μείνει ο δείκτης εντός περιοχής τιμών.

Δείτε στο πρόγραμμα που ακολουθεί: Φτιάχνουμε μια διάρθρωση μνήμης (Buffer) με 200 quaternion (τεραδόνια). Έχουμε ορίσει τι θα περιέχουν (τέσσερις double). Η βιβλιοθήκη περιμένει να έχουμε 4 double. Επειδή δηλώνουμε Clear οι τιμές σε όλους τους double μηδενίζουν (η μνήμη που ορίζουμε στη διάρθρωση καθαρίζει με 0 σε κάθε ψηφίο της). Οι διαρθρώσεις είναι αντικείμενα, τα οποία περιέχουν φυσική μνήμη. Το Quat(3) θα γυρίσει την διεύθυνση μνήμης του τέταρτου τεραδόνιου.
Για βοήθεια έχουμε μερικές λάμδα συναρτήσεις, οι οποίες μας εξυπηρετούν γιατί κρατούν το δείκτη στο αντικείμενο Διάρθρωση.
Δείτε ότι δεν διαγράφουμε την βιβλιοθήκη. Ειδικά η Math δεν διαγράφεται, απλά ο δείκτης σε αυτήν μπορεί να διαγραφεί. Μπορούμε να ορίζουμε την Math τοπικά όπου θέλουμε και πάλι το ίδιο αντικείμενο θα μας δώσει (δεν βγάζει νέο). Θα μπορούσε κανείς να φτιάξει μια δεύτερη βιβλιοθήκη με ίδιες συναρτήσεις κατ όνομα, και να δουλεύει το πρόγραμμα με μια αλλαγή στην γραμμή που ορίζουμε την Math (ώστε να οριστεί σε κάποια εξωτερική).



Module Checkit {
      \\ Math  Library Version 1.1
      \\ Math library is internal in M2000
      Declare Math Math
      With math, "Version" as Math.version
      Print "Math Version:", Math.Version
      structure Quaternion {
             w as double
             x as double
             y as double
             z as double
      }
      \\ A Buffer is a memory block
      Buffer Clear Quat as Quaternion*200
      Buffer Clear Doubles as Double*3
      \\ quaternions are  4x Doubles
      \\ get address to variables, so q is a pointer
      q=Quat(0)
      q1=Quat(1)
      q2=Quat(2)
      result=Quat(3)
      q1q2=Quat(4)
      q2q1=Quat(5)
      arr3=Quat(6)
      r=Doubles(0) ' this used for double
      \\ We use lambda with closure a pointer to Quat (a memory buffer)
      Quat.ToString$=lambda$ Quat (addr) ->{
            where=addr-Quat(0) ' we use it a byte offset (because of using as double)
            =format$("{0} + {1}i + {2}j + {3}k",Eval(Quat, where as double), Eval(Quat, where+8 as double), Eval(Quat, where+16 as double),Eval(Quat, where+24 as double))
      }
      PokeReal = lambda Doubles (addr, val) ->{
            where=addr-Doubles(0)
            Return Doubles, 0!where:= val as double
      }
      Real.ToString$=lambda$ Doubles (addr) -> {
            =format$("{0}",eval(Doubles, addr-Doubles(0) as double))
      }
      Call PokeReal(r, 7)
      Method Math, "Quaternion", q, 1,2,3,4
      Method Math, "Quaternion", q1, 2,3,4,5
      Method Math, "Quaternion", q2, 3,4,5,6
      Print "q = ";Quat.ToString$(q)
      Method Math, "QuatNormRetDouble", q as q.norm
      Print "Normal q = "; q.norm
      Method Math, "QuatNeg", q, result
      Print "Neg q = ";Quat.ToString$(result)
      Method Math, "QuatConj", q, result
      Print "Conj q = ";Quat.ToString$(result)
      Method Math, "QuatMultReal", q, r, result
      Print "Mul q 7 = ";Quat.ToString$(result)
      \\ r is pointer to double
      \\Method Math, "QuatAddReal", q, r, result
      \\ there is another way to pass value
      Method Math, "QuatAddByReal", q, 7, result
      Print "Add q 7 = ";Quat.ToString$(result)
      Print "q1 = ";Quat.ToString$(q1)
      Print "q2 = ";Quat.ToString$(q2)
      Method Math, "QuatMultQuat", q1, q2, q1q2
      Print "q1 * q2 =";Quat.ToString$(q1q2)
      Method Math, "QuatMultQuat", q2, q1, q2q1
      Print "q2 * q1 =";Quat.ToString$(q2q1)
      Print Real.ToString$(r)
      \\ using standard output (#0.0000), decimal point defined from locale)
      Locale 1033
      Method Math, "QuatString", q2q1 as q2q1.str$
      Print q2q1.str$
      Locale 1032
      Method Math, "QuatString", q2q1 as q2q1.str$
      Print q2q1.str$
      Method Math, "QuatString", q2q1, "#0.00"  as q2q1.str$
      Print "q2 * q1 =("+q2q1.str$+")"
      \\ using 6th quaternion from Quat (base 0, so 6th has index 5)
      Print eval(Quat, 5!w), eval(Quat, 5!x), eval(Quat, 5!y), eval(Quat, 5!z)
      Print "q = ";Quat.ToString$(q)
      Print "q1 = ";Quat.ToString$(q1)
      Print "q2 = ";Quat.ToString$(q2)
      Method Math, "QuatAddRealMulConst", 3, q, r
      Print "q = ";Quat.ToString$(q)
      Print "q1 = ";Quat.ToString$(q1)
      Print "q2 = ";Quat.ToString$(q2)
      Call PokeReal(r+8, -7)
      Call PokeReal(r+16, -14)
      \\ use an array of doubles
      Method Math, "QuatAddRealMulMul", 3, q, r
      Print "q = ";Quat.ToString$(q)
      Print "q1 = ";Quat.ToString$(q1)
      Print "q2 = ";Quat.ToString$(q2)
      \\ q=q*q, q1=q1*q1, q2=q2*q2
      Method Math, "QuatMultQuatMul", 3, q, q
      Print "q = ";Quat.ToString$(q)
      Print "q1 = ";Quat.ToString$(q1)
      Print "q2 = ";Quat.ToString$(q2)
      \\ Arr3=q*q, Arr3+32=q1*q1, Arr3+64=q2*q2
      Method Math, "QuatMultQuatMul", 3, q, q, Arr3
      Print "Arr3(0) = ";Quat.ToString$(Arr3)
      Print "Arr3(1)= ";Quat.ToString$(Arr3+32)
      Print "Arr3(2) = ";Quat.ToString$(Arr3+64)
}
Checkit





2. Αναβαθμίστηκε η γλώσσα σχετικά με τα νήματα, σε σχέδιο ταυτόχρονο, ή concurrent. Υπήρχε αυτό το σχέδιο μαζί με το διαδοχικό ή sequential, από την 5η έκδοση της γλώσσας (εδώ και τέσσερις εκδόσεις), αλλά δεν είχε προβλεφθεί ένα ζήτημα, το οποίο για να εξηγηθεί χρειάζεται μια εισαγωγή περί νημάτων, μικρή ωστόσο.

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

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

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

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

Ακολοθούν τα προγράμματα ελέγχου (δοκιμάστε τα σε παλαιότερη έκδοση).
Ο κώδικας είναι χωρίς χρώμα επίτηδες. Χρησιμοποιούμε το αυτόματο νήμα After ή Μετά το οποίο τρέχει μια φορά μετά το χρόνο που δίνουμε
Η λειτουργία γίνεται με τον διερμηνευτή στην εξορισμού ρύθμιση secure names ("+sec"). Αν την αλλάξουμε σε "-sec" θα δούμε το λάθος. Το λάθος βγαίνει στο z=m, όπου στο a$=key$ έχει κληθεί πάλι το beta και έχει αλλάξει η τιμή του m. Με το παλιό διερμηνευτή (υπάρχει για μέγιστη συμβατότητα), σε ορισμένες περιπτώσεις δεν υπάρχει δευτερο σετ στατικών, το x δηλαδή εμφανίζεται ίδιο και στο beta που καλείται από άλλο νήμα.

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

Κλήση τμημάτων με όνομα
thread.plan concurrent
set switches "+sec"
clear
module beta(m, k$) {
      static x=10, z=m
    
      if x=8 then a$=key$
      print z=m, x, k$, module.name$, module$
      x--
      if not empty then call beta, z
    
}
after 300 {
      beta 1, "a1", "b1", "c1"   
}
after 200 {
     beta 2,  "a", "b", "c"
}
wait 1000


Κλήση τμημάτων με την Κάλεσε (Call)
thread.plan concurrent
set switches "+sec"
clear
function beta(m, k$) {
      static x=10, z=m
     
      if x=9 then a$=key$
      print z=m, x, k$, module.name$, module$
      x--
      if not empty then call beta(z)
     
}
after 300 {
      call beta( 1, "a1", "b1", "c1" )
}
after 200 {
     call beta( 2,  "a", "b", "c")
}
wait 1000


Δοκιμάστε το και όταν ο κώδικας αυτός περιέχεται σε εσωτερικό τμήμα:
module checkit {
      thread.plan concurrent
      set switches "+sec"
      clear
      module beta(m, k$) {
            static x=10, z=m
            if x=8 then a$=key$
            print z=m, x, k$, module.name$, module$
            x--
            if not empty then call beta, z
      }
      after 300 {
       call   beta 1, "a1", "b1", "c1"    
      }
      after 200 {
        call   beta 2,  "a", "b", "c"
      }
      wait 1000
}
checkit




Κλήση συνάρτησης ως τμήμα με την Κάλεσε (Call), εδώ η συνάρτηση παίρνει το σωρό τιμών του νήματος.
thread.plan concurrent
set switches "+sec"
clear
function beta(m, k$) {
      static x=10, z=m
     
      if x=9 then a$=key$
      print z=m, x, k$, module.name$, module$
      x--
      if not empty then call beta(z)
     
}
after 300 {
      call beta( 1, "a1", "b1", "c1" )
}
after 200 {
     call beta( 2,  "a", "b", "c")
}
wait 1000


Από εξωτερικό τμήμα:

module checkit {
      thread.plan concurrent
      set switches "+sec"
      clear
      function beta(m, k$) {
            static x=10, z=m
           
            if x=9 then a$=key$
            print z=m, x, k$, module.name$, module$
            x--
            if not empty then call beta(z)
           
      }
      after 300 {
            call beta( 1, "a1", "b1", "c1" )
      }
      after 200 {
           call beta( 2,  "a", "b", "c")
      }
      wait 1000
     
}
call checkit 



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

thread.plan concurrent
      set switches "+sec"
      clear
      function beta(m, k$) {
            static x=10, z=m
           
            if x=9 then a$=key$
            print z=m, x, k$, module.name$, module$
            x--
            =x
            if not empty then =beta(z, ![])+x
                       
      }
      after 300 {
            m=beta( 1, "a1", "b1", "c1" )
      }
      after 200 {
           m=beta( 2,  "a", "b", "c")
      }
      wait 1000


Και από εσωτερικό τμήμα:
module checkit {
      thread.plan concurrent
            set switches "+sec"
            clear
            function beta(m, k$) {
                  static x=10, z=m
                 
                  if x=9 then a$=key$
                  print z=m, x, k$, module.name$, module$
                  x--
                  =x
                  if not empty then =beta(z, ![])+x
                             
            }
            after 300 {
                  m=beta( 1, "a1", "b1", "c1" )
            }
            after 200 {
                 m=beta( 2,  "a", "b", "c")
            }
            wait 1000   
}
checkit


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


thread.plan concurrent
      set switches "+sec"
      clear
      beta =lambda X=10, z=-1 (m, k$) -> {
               if z=-1 then z=m
           
            if x=9 then a$=key$
            print z=m, x, k$, module.name$, module$
            x--
            =x
            if not empty then =lambda(z, ![])+x
                       
      }
      beta1=beta
      after 300 {
            m=beta( 1, "a1", "b1", "c1" )
      }
      after 200 {
           m=beta1( 2,  "a", "b", "c")
      }
      wait 1000


Και από εσωτερικό τμήμα

module checkit {
thread.plan concurrent
      set switches "+sec"
      clear
      beta =lambda X=10, z=-1 (m, k$) -> {
               if z=-1 then z=m
           
            if x=9 then a$=key$
            print z=m, x, k$, module.name$, module$
            x--
            =x
            if not empty then =lambda(z, ![])+x
                       
      }
      beta1=beta
      after 300 {
            m=beta( 1, "a1", "b1", "c1" )
      }
      after 200 {
           m=beta1( 2,  "a", "b", "c")
      }
      wait 1000

}
checkit