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

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

Προστέθηκε η αλλαγή βάσης για τους πίνακες. Μπορούν να συνυπάρχουν πίνακες με βάση 0 και πίνακες με βάση 1. Εξ ορισμού η βάση είναι 0.

μ=Λάμδα Χ=1 ->{=Χ : Χ++}
Βάση 1
Πίνακας Α(10)<<μ() ' 1 .. 10
Για ι=1 έως 10 : Τύπωσε Α(ι), : Επόμενο ι
Τύπωσε
Βάση 0
Πίνακας Β(10)<<μ() ' 11 .. 20
Για ι=0 έως 9 : Τύπωσε Β(ι), : Επόμενο ι
Τύπωσε
Τύπωσε Έγκυρο(Α(0)), Έγκυρο(Β(10)) \\ 0  0
Τύπωσε Έγκυρο(Α(10)), Έγκυρο(Β(0)) \\ -1  -1 (αληθές)



Προστέθηκε η συντόμευση της Προς στην εντολή Αν Τότε, μόνο για αριθμητικές ετικέτες (και όταν δεν χρησιμοποιούμε μπλοκ}. Στο παράδειγμα φαίνονται και αριθμοί γραμμών (Η Μ2000 δέχεται και αριθμούς γραμμών μέχρι 5 ψηφία, το 050 μπορεί να κληθεί με το 50)

050 α=Τυχαίος(1, 40)
100 Αν α<20 Τότε 300
200 Προς 350
300 Τύπωσε "οκ" : Έξοδος
350 Τύπωσε "γεια"
400 Τέλος


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

Κλάση Άλφα {
      Πίνακας Α(10)=5
      Χ=4,Υ=3
      Συνάρτηση Όλα {
            =.Α(Αριθμός)*.Χ+.Υ
      }
}
Μ=Άλφα()
Μ.Α(3)=100
Τύπωσε Μ.Όλα(3) \\403
\\ Φτιάχνω πίνακα με αντικείμενα με κοινές συναρτήσεις
Πίνακας Α(10)=Άλφα()
\\ βάζω τιμή στο αντικείμενο Α(1) στο πίνακά του Α(), στο Α(3)
Α(1).Α(3)=100
Τύπωσε Α(1).Όλα(3) \\403
Τύπωσε Α(0).Όλα(3) \\23
\\ Τώρα φτιάχνω πίνακα χωρίς να τον γεμίσω με ένα αντικείμενο
Πίνακας Β(10)
\\ Και απλά αντιγράφω το αντικείμενο από το Α(1) στο Β(1)
Β(1)=Α(1)
\\ στη προηγούμενη αναθεώρηση δεν έρχονταν και η συνάρτηση Όλα()
Τύπωσε Β(1).Όλα(3) \\403
\\ Τώρα αντιγράφω το Α(0) στο Β(1)
Β(1)=Α(0)
Τύπωσε Β(1).Όλα(3) \\23


Ανανεώθηκε η βοήθεια (μερικά στοιχεία επικαιροποιήθηκαν)

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

Examples using Thread.Plan

By default threads in M2000 uses Plan Sequential. Each thread get time to run all code inside.  Another plan is the concurrent where execution of other threads can happen when execution of a thread is happen but not finished. We can use curly brackets  { } for commands that we want to run sequential. Here in the examples we have a situation when we put two commands after Then in an If Then structure. Normaly after then and until the end of the line we call each command if condition is true. But in concurrent run the thread exit for a while to give time to other threads, and forget the rule! So we need a block { } to make them run as one command after  "Then"

In these examples we use static variables for each thread, one for counting for exit the thread by erasing, and other to keep info about thread handler (a number from M2000 environment's task manager). Static variables can't exist with module local variables with same name . Also we see that definitions for threads are done inside a normal  routine like Basic's  Gosub Return (M2000 has subroutines also, Sub name() ...End Sub)


Try these examples using M2000 interpreter. Just write Edit A and copy the commands, then press Esc and write A to start it.
Newest version of M2000 not allow a static variable with same name as a local variable. But we can make as much threads we want with same static variable name (but each variable are static in one thread only). Control for error happen in Static command. Thread.Plan Sequential
' A=100 \\ NEW VERSION THIS PRODUCE ERROR, AT STATIC COMMAND
M=500
N=0
Gosub StartThreads
\\ using a thread for this task.
\\ we can exit by using mouse click or counting threads give zero
Task.Main 50 {
      Threads
      Refresh
      if mouse or N=0 then exit
}
Threads
End
StartThreads:
For K=1 to 20 {
      N++
      Thread {
            Print A*M, B \\ static A is used before any local A
            A--
            \\ changing thread plan we have a problem because
            \\ thread this erase is executed without control from If
            \\ so we need to use block { N-- : thread this erase }
            \\ blocks are executed before task manager change thread
            If A=0 then N-- : thread this erase
      } as T execute static A=10, B=T
      \\ Now we start thread
      Thread T interval 100
}
Return


Second example show Concourrent Plan.

Thread.Plan Concurrent
M=500
N=0
Gosub StartThreads
\\ using a thread for this task.
\\ we can exit by using mouse click or counting threads give zero
Task.Main 50 {
      Threads
      Refresh
      if mouse or N=0 then exit
}
Threads


End
StartThreads:
For K=1 to 20 {
      N++
      Thread {
            Print A*M, B
            A--
            Print ">>", N
            \\ block needed after then if concurrent plan used
            If A=0 then { N-- : thread this erase }
      } as T execute static A=10, B=T
      \\ Now we start thread
      Thread T interval random(10,100)
}
Return


Third example is like second one. We see a change of normal routine with a Sub Routine, also we see from threads we can call Display(), a module's subroutine. Subrutines uses modules namespace (so can see modules variables which is the same for all threads, but run in thread exexution object, so they can see static variables (these are per execution object). Defining variables in threads can be done, but it is proper to that temporary, using For this { } or calling a subroutine (any new definition erased in a subroutine, but no in a simple routine like one in two examples above). Threads are not erased by subroutines, they erased by using Threads Erase, or by using Thread N erase, or by the end of execution of thread parent. Because we can define threads in threads, these inner threads are not erased in exit of the parent module, so we use Threads Erase to erase them.

Thread.Plan Concurrent
M=500
N=0
StartThreads(20)
\\ using a thread for this task.
\\ we can exit by using mouse click or counting threads give zero
Task.Main 50 {
      Threads
      Refresh
      if mouse or N=0 then exit
}
Threads


End
Sub Display()
      Print ">>", N
End Sub
Sub StartThreads(Many)
      For K=1 to Many {
            N++
            Thread {
                  Print A*M, B
                  A--
                  Display()
                  \\ block needed after then if concurrent plan used
                  If A=0 then { N-- : thread this erase }
            } as T execute static A=10, B=T
            \\ Now we start thread
            Thread T interval random(10,100)
      }
End Sub


Commands for threads, except Erase, Interval and Execute (this is an out of order execute, an execute when target thread is idle) are Hold, Restart.

Κυριακή 29 Ιανουαρίου 2017

An example showing stream operator in M2000

Operator << used here to add to a function a generator, another function to supply a stream of values. Also we see the use of Event object.

Stream operator used for arrays to feed each element, but mainly used for what we see here.

We can make some minor changes and we get a simpler version, without TankControl Group (an object in M2000), and with no Event too. Just delete Line "Group TankControl".., line "Event Probe ..", line "Call Event .Probe...", we have to delete the closing curly bracket (for deleted Group definition) before line "Class SpecificClass...", then line "Event TankControl.Probe....", and we have to change the line "For TankControl" with "For This" (so dot before alfa has a meaning This, or we through For  { } , but keeping inside all the code, because by default a single dot interpreted as This. Keep in mind that a For { } not only tag what is a dot but also make all definitions inside block for temporary use, but here we don't have that issue)

\\ we have a function to simulate a tank quantity change
\\ alfa arguments are:
\\ current tank quantity, optionally quantity (30 by default) to remove if valve is open,
\\ a flag for printing messages (false by default)
\\ and optionally we can pass  as many as we want valve states, true for open, false for closed
\\ we can use the << operator (stream operator) to send valve state
\\ we make a class and a group from that class, named Specific
\\ We can feed Specific with a pattern of valve states (a batch of patterns)
\\ We have 4 options. We can send one pattern as a batch, one time or many (2 options),
\\ or we can send one state at a time for one batch or form many.
\\ We can expand this logic, if we move function's alfa definiton in a group where we put an Event object.
\\ so we can use Event through alfa to stop Specific at some level of tank quantity
LowLevelSet=500
Read ? LowLevelSet \\ read optionally
Group TankControl {
      Event Probe { Read tank_quantity, &exitvalue }
      Function alfa {
            Read tank
            Let quantity=30, messages=false
            Read ? quantity, messages
            exitnow=false
            {
                  Try Stream
                  If empty or tank=0 Then exit
                  Call Event .Probe, tank, &exitnow
                  if exitnow then exit
                  If number Then tank-=quantity : If messages Then Print "Valve open"
                  If tank<0 Then tank=0
                  If messages Then Print format$("Tank quantity={0}", tank)
               
                  Loop
            }
            =tank
      }
}
Class SpecificClass {
Private:
      Dim A()
      myCursor=-1
      many=10
      once, counter, step_cursor
      stepcounter
Public:
      Module SpecificClass {
            .ReSet
      }
      Module ReSet {
            Read ? .many
            Dim .A(.many)=False
            .myCursor<=-1
      }
      Function Feed {
            =True
            .myCursor++
            While .myCursor<.many {
                  If Empty Then Exit
                  Read .A(.myCursor)
                  .myCursor++
               
            }
            If Not Empty Then =False : .myCursor<=.many-1
            .once<=True
      }
      Function ReadAllonce {
            If not .once Then exit
            .once<=False
            If .myCursor>0 Then
            For i=0 to .myCursor { Data .A(i) }
            .counter++
      }
      Function ReadAllmany {
            If .myCursor>0 Then
            For i=0 to .myCursor { Data .A(i) }
            .counter++
      }
      Function ReadOneAtime_once {
            If not .once Then exit
            If .myCursor>0 Then {
                If .step_cursor>.myCursor Then {
                 .once<=False
                 } Else {
                        Data .A(.step_cursor)
                        .stepcounter++
                        .step_cursor++
                 }
            } Else .once<=False
      }
      Function ReadOneAtime_many {
            If .myCursor>0 Then {
                  If .step_cursor>.myCursor Then .ResetStep
                  Data .A(.step_cursor)
                  .stepcounter++
                  .step_cursor++
            }
      }
      Module ResetStep {.step_cursor<=0}
      Module UnlockOnce {.once<=True : .step_cursor<=0}
      Module PrintStepCounter { Print .stepcounter }
}
Specific=SpecificClass()
Function LowLevel {
      \\ need same signature for event
      Read New TankLevel, &exitvalue
      exitvalue=TankLevel<LowLevelSet
}
\\ using Lazy(&LowLevel()) and not LowLevel(), we make the call like the code was in module, so we read LowLevelSet.
\\ and of cource we can tweak the Specific object
Event TankControl.Probe New lazy$(&LowLevel())


Print "Start"
For TankControl {
      If Specific.Feed(True, False, False, True,False,False, True,True) Then {
            Last=.alfa(1000, 35, True)<<Specific.ReadAllonce()
            \\ here we pass manual values
            Last=.alfa(Last, 100, True, True, False, False, True)
            Specific.UnlockOnce
            Last=.alfa(Last, 35, True)<<Specific.ReadAllonce()
            Last=.alfa(Last, 35, True)<<Specific.ReadOneAtime_once()
            Specific.ResetStep
            If Last>0 Then {
                  If Ask("try to empty tank?", "Tank")=1 Then {
                        \\ Last=.alfa(last, 35, True)<<Specific.ReadAllmany()
                        Last=.alfa(last, 35, True)<<Specific.ReadOneAtime_many()
                        Specific.PrintStepCounter
                  }
            }  
      }
}



Σάββατο 28 Ιανουαρίου 2017

Αναθεώρηση 14 (έκδοση 8.2)

1. Μικρές προσθήκες/διορθώσεις. Προστέθηκε στη βοήθεια το Inventory/Κατάσταση, το Buffer/Διάρθρωση, το Λάμδα/Lambda, το Event/Γεγονός.
Γράφουμε Βοήθεια Κατάσταση και μας δίνει η Μ2000 παραδείγματα για να καταλάβουμε πως τα χρησιμοποιούμε.

2. Διορθώθηκε η εντολή:
Εκτυπωτής ?
Τώρα γίνεται επιλογή απευθείας από τη λίστα.

3. Μπήκε εμφάνιση λάθους αν έχουμε υπερχείλιση μακρύ (Long).

4. Μπήκε έλεγχος (εμφάνιση λάθους) αν πάμε σε ένα αντικείμενο να βάλουμε ένα αντικείμενο άλλου τύπου (στις λάμδα συναρτήσεις και στις ομάδες).




Κυριακή 22 Ιανουαρίου 2017

Αναθεώρηση 13 (έκδοση 8.2)

Revision 13, for version 8.2

\\ This is an advanced example of using events, and references
\\ M2000 never expose actual references.
\\ All items are searched by a hash function internal,
\\ using name of item and module name
\\ (maybe that name changed internal from interpreter)
\\ function weak$() return the internal name of any item included array item.
\\
\\ To run this write in M2000 CLI> edit a <enter> and then copy this
\\ press Esc and write a <enter> to run
\\ use Save pr1 <enter> to save it

\\ Nothing is static in M2000, except for "running" code.
\\ so Module deep1 isn't exist until first we make it a module to call
\\ and then when we call it, make anything as it runs
\\ Three steps: part of a source - source with a name - call that name
\\ M2000 interpreter use always source, never made any code of it.
\\ Using the source M2000 makes real objects and execute command on those.
\\
\\ Groups are static objects as list of items (we can reference specific item)
\\ ... like variables, modules, functions, events, lambdas, etc
\\ Here the task is to raise an event from an object (Call Event)
\\ and sending a value to this and to another object, calling functions
\\ and each function read a property y (a variable in the group)
\\ We test the raise of event when we pass the object (group)
\\ by value, by referenec, by weak reference
\\ and then we put copies of these groups in an array, and return it
\\ Then we fix the references, in the new copied array, and test again
\\ the raise of event from stored group (in array) and from passing
\\ with weak reference to another module.

Module deep1 {
      Group aa {
            y=123
            Event b { Read x }
            Function aa { Read x : Print x+.y }
            Module callme {
                  Call Event .b, number
            }
      }
      Group bb {
            y=456
            Function bb { Read x : Print x+.y}
      }
      Event aa.b New aa.aa(), bb.bb()
      Print "From Module a"
      aa.callme 5
      Module testme {
            Read c
            Print "From testme inside Module Deep1"
            c.callme
      }
      \\ Here we copy aa Group to c
      testme aa, 5
      \\  133
      \\ 466
      \\ 128
      \\ 461  (here is the fix, old versions print 128)
      \\ passing by reference was ok
      Module testme2 {
            Read &c
            Print "From testme2 inside Module Deep1"
            c.callme
      }
      testme2 &aa, 5
      \\ using weak reference was ok too
      \\ no copy or reference for each element in Group aa
      \\ just Call it like it is a global Module (using c$ as prefix value)
      Module testme3 {
            Read c$
            Print "From testme3 inside Module Deep1"
            c$.callme
      }
      testme3 &aa, 5
     
      \\ we can put copies of static objects in arrays items
      Print "Test Event from object in item in array"
      Dim A(10)
      A(0)=aa
      A(0).y=1000
      A(0).callme 5
      testme3 weak$(A(0)), 5
      \\ if array returned from this Module then event find error
      \\ because group bb deleted.
      A(1)=bb
      push A()
}
Deep1
\\ now all modules and variables in Deep1 are destroyed
\\ except stack values. And in stack we have an array
Print StackType$(1) \\ print mArray - the inside object for arrays in M2000
Print Match("A") \\ Print -1 (True), is Array
Dim A()
\\ first we create the array and then we put the object on it
Read A()
Print "From exported array"
\\ need to restore weak reference
For A(0) {
      \\ this block make A(0) static with a hidden name
      \\ and this name used every time
      Event .b Clear \\ clear all functions in event chain
      \\ here we don't need to give a lazy$() function.
      Event .b New .aa()
      \\ function lazy$() return an anonymus function with lazy evaluation
      \\ when this anonymus function run, set the module name to A
      \\ so A(1) can be found, also we have to write the parameters to pass
      Event .b New lazy$(A(1).bb(number))
     \\ this happen because we can't get reference from array items.
    
}
\\ Now we Call a non static group
Print "From Module a"
A(0).callme 15
Module testme3 {
      Read c$
      Print "From testme3 inside Module a"
      c$.callme
}
\\ Now we send it to module testme3 (module's deep1 modules are erased)
testme3 Weak$(A(0)), 15
\\ so now we have two objects, non static, but for this momemt they have
\\ one point static...the name of the array (A() is inside the module a)
\\ event b is calling from A(0) and opens A(1) reading variabe (property) y.
\\ Events may have by reference values as parameters and this works with multicast

Σάββατο 21 Ιανουαρίου 2017

Αναθεώρηση 12 (έκδοση 8,2)

Προσθήκη στη γλώσσα για τους πίνακες ακεραίων και αλφαριθμητικών:
Μπορούμε να βάλουμε πίνακα στη θέση στοιχείου:


Dim a$(10)="No"
Dim b$(5)="Yes"
a$(0)=b$()
Print a$(0)(0) \\ Yes
a$(0)(1)="Hello"
Print a$(0)(1), a$(1) \\ Hello No

Dim a%(10)
a%(0)=function({{=10,11,12,13,14,15,16}})
Print a%(0)(3) \\13
a%(0)(3)+=1000
Print a%(0)(3) \\1013

Για πραγματικούς λειτουργούσε και στην αναθεώρηση 11

Dim a(10)
a(0)=function({{=10,11,12,13,14,15,16}})
Print a(0)(3) \\13
a(0)(3)+=1000
Print a(0)(3) \\1013
 

Στη Μ2000 όταν επιστρέφουμε δυο ή περισσότερες τιμές σε συνάρτηση τότε αυτές γράφονται σε πίνακα και επιστρέφει ο πίνακας. Η συνάρτηση function() δέχεται σαν όρισμα όνομα συνάρτησης και χωριστά τις παραμέτρους, ή ανώνυμη συνάρτηση. Μια ανώνυμη συνάρτηση είναι ένα αλφαριθμητικό με πρώτο χαρακτήρα μια αγκύλη. Τα αλφαριθμητικά στη Μ2000 μπαίνουν ή με διπλό εισαγωγικό αρχή και τέλος ή με αγκύλες { }. Εδώ η πρώτη αγκύλη δηλώνει ότι ακολουθεί αλφαριθμητικό, και η δεύτερη δηλώνει ότι έχει συνάρτηση (αυτό το καταλαβαίνει η function() ή συνάρτηση()). Μέσα στις διπλές αγκύλες έχουμε μόνο το = στην αρχή της εντολής (σημαίνει επιστροφή τιμής) και ακολουθούν εκφράσεις -εδώ αριθμοί- χωρισμένοι με κόμματα. Υπάρχει και η function$() για να επιστρέφει αλφαριθμητικά.

Έχει ενημερωθεί το git και το dropbox.

 

Πέμπτη 19 Ιανουαρίου 2017

Ύψωση σε δύναμη και πρόσημο!


Στο παράδειγμα έχουμε τρεις μεταβλητές και τυπώνουμε το περιεχόμενό τους, όπως το έχουμε διαμορφώσει από ισάριθμες εντολές καταχώρησης του τύπου μεταβλητή = έκφραση.
a=-9**2
? a \\ 81
b
=0+-9**2
? b \\ 81
c
=0-9**2
? c \\ -81
Το -9 στη δευτέρα (-9 ** 2) είναι το -9 * -9 άρα το 81 (θετικό πρόσημο), στην a φαίνεται ξεκάθαρα. Στην b έχουμε δυο πρόσημα, το + και το -. Το πρώτο πρόσημο λέει να προσθέσουμε το επόμενο και το επόμενο είναι το -9**2 άρα το 81. Στο c έχουμε το – που σημαίνει “Αφαίρεσε” το 9**2 από το 0. άρα δίνει το 0-81 ή -81.
b1=0+(-9**2)
? b1
Εδώ στο b1 φαίνεται πως ο εκτιμητής παραστάσεων ενεργεί με παρενθέσεις, και είναι το ίδιο με το 0+-9**2, όπου το + επειδή είναι μετά το 0 λέει απλά “πρόσθεσε το παρακάτω -9**2”
Στη Μ2000 η ύψωση σε δύναμη γίνεται και με τον χαρακτήρα ^ (shift 6)
a=-9^2
? a \\ 81
b=0+-9^2
? b \\ 81
b1=0+(-9^2)
? b1
c=0-9^2
? c \\ -81

Μπορούμε στο μέρος της δύναμης να βάλουμε παρενθέσεις αλλά όχι πρόσημο πριν την παρένθεση θα χαθεί! Μέσα στην παρένθεση βάζουμε όποια έκφραση θέλουμε, ακόμα και αρνητικό (με μηδέν μας δίνει 1, ότι υψώσουμε σε 0 θα δώσει 1)
? 2-3**(2), 2-3**(-4)
Το ? 0^0 δίνει 1
Άλλα παραδείγματα:
? 2**-2,3*2**-2, 3/2**2 \\ .25, .75, .75
? (3/2)**2 , 3**2/2**2 \\ 2.25, 2.25
? 3**2-2**2+1 \\6
? (3**2)-(2**2)+1 \\6