Τετάρτη 11 Μαρτίου 2026

A SetTimeout functionality for M2000

This program  run two loops for i from 0 to 7 (last value after loop is 8). For each body of loop we make a call for a function using the i value, after 1 second. The first loop has a lambda function which can hold i as a closure with the "then" value. In the second loop we make a lazy evaluation block, where the body of the function is exactly a part of the module (we can see variables, like i, and anything we make there including subs but not for this example)

Although a normal function has own name space, there are other functions:

1) A lambda function has two parts, the list of closures (can be empty) and the function body same as the body of a normal function. The closures are like local to body. We can use lambda() to call recursive and the closures are the same for each call (so the closures are local but for all calls in a recursive manner). Each call in the series of call may or may not have the same stack of values. If we use Call statement we pass the same stack of values (with the passing parameters at the top, from we read first values). If we use the function in an expression then a new stack of values attached to function (so we can use this for any number of parameters, so the parameters which not used deleted). This functionality for stack of values are the same as for the normal function.

2) A simple function. This function has format like Sub, using Function name()  and in an another line the End Function. We call @name() and the name has not to be same as the internal functions. This type cannot passed by reference and cannot used with Call statement. This type use the same stack of values from the caller. This type also has to use Local to create local variables, because luck a namespace (it use the callers namespace). This function can be called from the module/function which exist - always at the bottom side of the code, the same side we put the Subs. Also this function can be called from a module/function which we define as child module/function and there is no a function with the same name at these children (so we can reuse a function from multiple child modules/funcitons.

3)A "dummy" function, is a body of function which run as a module with or without same stack of values. The function isn't dummy if we use it like all functions. But here we use the Lazy$() which make a special reference bounding a reference to the specific namespace (same as the one where the Lazy$() executed). We can use Lazy$() using a formula like Lazy$(x+y). The example below show a a way to use a Group as a value used as a call back (we call the Inner module and from the Inner we call back before the Inner module end execution and return, and here we call the Value part of Group Counter which alter the Counter.count variable)  

Module TestLazy {
Group Counter {
count=0
Value {
=.count
.count++
}
}
x=10
y=3
Module Inner(&a()) {
Print a()
Print a()
}
Inner lazy$(x+y+Counter) ' return 13 then 14
Inner lazy$(x+y+Counter) ' return 15 then 16
Print Counter.count=4 ' true
}
TestLazy


This is the example for "dummy" function (this is a way to have a call back, which mean we call the Inner module and from the Inner we call back before the Inner module end execution and return)

Module TestDummyFunction {
flush
i=100
function aa(x) {
=x+i
}
Module Inner(&a()) {
Print a(10)+Stack.size

}
Function Inner2(&a()) {
Print a(10)+Stack.size
=0
}
Push 1,2,3
Inner Lazy$(&aa()) ' 113 (110 + 3)
M=Inner2(Lazy$(&aa())) ' 110 (110 + 0)
Print Number, Number, Number ' pop 3,2,1
' not valid because now we call it like a normal function
Print Valid(aa(10))=0 ' true
Try ok {
Call aa(10)
}
' Unkown Variable I Missing Number Exrpession
Print "Finish:"+If$(ok or Error -> Error$, "ok")
}
TestDummyFunction


About Threads


The main example, has two different setTimeout, one for lambda function and another one for a reference of function (we can pass the Lazy$() value which always a reference of function.

When we use the first one, we pass a copy of lambda in the Thread Stack of values (each thread has a body at the same namespace as the one which made it, le say the parent, a stack of values different from the parent, and maybe has a list of static values (always with different name from local variables). The body of thread executed in each interval. By default we use Thread.Plan Sequential  (not executed here, because by default it this plan - not the concurrent plan). We can terminate a thread through the thread using the Thread This Erase statement. Each thread has a number so the N variable hold the number, but here we don't need this number, we can erase the thread after the first run. Also we place a value on threads stack. This can be done using the Thread N Execute using statements to execute for threads stack of values. (also we can make Static variables here. but these cannot have names of local variables like i).

Anything we make in a Thread may or may not be used next time. If we exclude the For this { } block (used for temporary definitions) we can also exclude the New in Read statement (normally a reference can't be assigned second time, but this not apply to functions references) but we get different output, because the Print a() (last statement to execute) find the last a() body which get from reference. So using New for Read (Read New) we make always new definitions which shadow old definitions. So we use the temporary block (For this { }  block) to delete the new definition when we do not use it. So now the last statement print 1234 (the function a() preserved)


The examples for Javascript are from https://gist.github.com/mirajehossain/js.md


Thread.Plan Sequential  ' this is by default
Module TestSetTimeOut {
' Normaly a function has own namespace
i=100
function a() {
=1234
}
function checkit() {
i=555
Print i
}
Call checkit()
Print i=100 ' true
Rem { // Javascript
        for (let i = 0; i < 7; ++i) {
          setTimeout(function () {
            console.log(i);
            // => 0
            // => 1
            // => 2
            // => 3
            // => 4
            // => 5
            // => 6
            // => 7
          }, 1000);
        }
}

' like Let in Javascript we place current i to F, so we get after the loop all values again.
for i=0 to 7
print "value:";i : Refresh
F=lambda i -> {
Print i:Refresh
}
SetTimeOut(F, 1000)
' SetTimeOut((lambda i -> {Print i, "OK":Refresh}), 1000)
next i
WaitThreads()
Rem { // Javascript
        for (var i = 0; i < 7; ++i) {
          setTimeout(function () {
            console.log(i);
            // => 8
            // => 8
            // => 8
            // => 8
            // => 8
            // => 8
            // => 8
            // => 8
          }, 1000);
        }
}
' like Var we get the last value of i (which is 8) for all calls through threads
' becaue we pass the same i as the one which exist.
for i=0 to 7
print "value:";i : Refresh
function enviroment {
Print i:Refresh
}
function enviroment2 {
Print i, "OK":Refresh
}
SetTimeOutVar(Lazy$(&enviroment()), 1000)
' SetTimeOutVar(Lazy$(&enviroment2()), 1000)
next i
WaitThreads()
' Bonus stage
' We can pass by reference the lambda function, as function reference.
' But we get always the same reference, so we get the last F with i=7
for i=0 to 7
print "value:";i : Refresh
F=lambda i -> {
Print i:Refresh
}
SetTimeOutVar(&F(), 1000)
next i
WaitThreads()
Print a()
Sub SetTimeOut(f as lambda, msec)
Local N
thread {
for this { ' we erase the function after exit this block
Read New a
Call a()
}
Thread this Erase
} as N
Thread N Execute Push f
Thread N interval msec
End Sub
Sub SetTimeOutVar(f$, msec)
Local N
thread {
For This { ' we erase the function after exit this block
Read New &a()
Call a()
}
Thread this Erase
} as N
Thread N Execute Push f$
Thread N interval msec
End Sub
Sub WaitThreads()
main.task 10 {}
End Sub
}
TestSetTimeOut

Fast Fourier transform using complex type

 

There is a post here (which updated by me) : https://rosettacode.org/wiki/Fast_Fourier_transform#M2000_Interpreter

M2000 use Complex type native. Look at Sub FFT we can use as *Complex[] to restrict the parameter to be a pointer to a RefArray type of Complex type. Because we pass a pointer by value, the RefArray values are like passed by reference, because we alter values. We need this because in other recursive calls we exchange the pointers (out in place of buf and puf in place of out).

module FFT {
' print $("0.000", 16)   ' #1 (use #1, #2, #3 for 4 decimals for printing numbers )
locale 1033
open "output.txt" for wide output as #F
complex buf[7], out[7]
buf[0]|r = 1: buf[1]|r = 1: buf[2]|r = 1: buf[3] = (1, 0i)
showArr(buf, "Input")
FFT(out, buf, 0, 1, 8)
ShowArr(out, "Output")
' print $("") ' #2
close #F
print #-2, eval$(buffer(dir$+"output.txt"))
Sub ShowArr(m, mes as string)
local n, mx=len(m)
print #F, mes;": (real imag abs)"
while n<mx
' print m[n]  ' #3
' round(number) round to 13th decimal, is same as round(exp, 13)
' modulus of complex number: Mod(complex)
print #F, format$("{0:0:-10} {1:-10} {2:-12}",m[n]|r, round(m[n]|i, 4)+"", round(mod(m[n]), 8)+"")
n++
end while
End Sub
Sub FFT()
Shift 5
Read New N as long
FFT1()
End Sub
' FFT1() use N always
Sub FFT1(buf as *Complex[], out as *Complex[], begin as Long, stp as Long)
If stp < N Then
FFT1(out, buf, begin, 2 * stp)
FFT1(out, buf, begin + stp, 2 * stp)
Local i as long, t as complex
for i=0 to N-1 step 2*stp
t = Polar(1, -pi* i / N) * out[begin + i + stp]
buf[begin + i div 2] = out[begin + i] + t
buf[begin + (i + N) div 2] = out[begin + i] - t
next
End If
End Sub
}
FFT

Output.txt

Input: (real imag abs) 1 0 1 1 0 1 1 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 Output: (real imag abs) 4 0 4 1 -2.4142 2.61312593 0 0 0 1 -0.4142 1.0823922 0 0 0 1 0.4142 1.0823922 0 0 0 1 2.4142 2.61312593



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

English Lesson 1

 This program need two different voices (voice 1 male, voice 2 female). Windows 11 and 10 have two.

place these on a module say a. 

Edit a

Then copy this code, then press Esc to close editor, then type a to run it. This program terminate with Esc.


Escape Off
Const proportional = 4, terminal_style = 0
Volume 100
Form 60
Pen 14
Cls #ff2000
Print $(proportional),
Double
Print "English Lesson 1"
Normal
Cls 5, row
Refresh
For i=1 to Speech {
      Print "Voice "+i+": "+Speech$(i)
}
if instr(Speech$(1),"Zira")=0 then
Const male=1, female=2
else
Const male=2, female=1
end if
Const on=1, off=0
Flush
Data ("George","Athens", male, false)
Data ("Alexander", "Marusi", male, true)
Data ("Katerina", "Marusi", female, true)
database=array([])


If Speech<2 Then Print "I need two voices at least": Goto exit1
Speech {<silence msec="500"/>}  ' start engine and pause for half second.
do
Italic on : Pen #AAAA00 {Print "Hold Esc to Exit"}: Italic off
a=database#Val(Random(0,2))
Say("Teacher","Hi; What"+If$(Random(1,2)->"'s", " is")+" your name?", 2)
Say(a#Val$(0),"Hello; My name is "+a#Val$(0)+".", a#Val(2), a#Val(3))
If Keypress(27) Then Exit
Say("Teacher","Where are you from, "+a#Val$(0)+"?", 2)
Say(a#Val$(0),"I"+If$(Random(1,2)->"'m", " am")+" from "+@emph$(a#Val$(1))+".", a#Val(2), a#Val(3))
If Keypress(27) Then Exit
Always
Pen #AAbb77 {
Say("Teacher","That's it for today. "+@emph$("Goodbye."), 2)
}
exit1:
Print $(terminal_style),
While Keypress(27) {Wait 10}
Escape on
End
Function emph$(a$)
="<emph>"+a$+"</emph>"
End Function
Function clear$(a$)
Local b=1, c
Do
b=Instr(a$, "<", b)
If b>0 Then
c=Instr(a$, ">", b+1)
If c>0 Then
Insert b, c-b+1 a$=""
Else
b=0
End If
Else
b=0
End If
When b>0
=a$
End Function
Sub Say(who$, that$, gender as integer, teen as boolean=false)
Print who$+": "+@clear$(that$)
Refresh
If teen Then
Speech ";"+that$!, gender
Else
Speech ";"+that$, gender
End If
End Sub


Τρίτη 24 Φεβρουαρίου 2026

Revision 7 Version 14

 I found a problem when I use the ip 142.250.187.100 for test but now not responding. This affect then  read only variables named INTERNET and INTERNET$. Revision 7 fix the problem.


We can bypass INTERNET functionality by using a global group INTERNET which return a value (so call a function without using parenthesis postfix on the name):

global Internet=lambda (a$="100")-> {
group a {
ip$="142.250.187."+a$
value {
declare client client
With client, "NoError", True
Method client, "SetTimeouts", 100, 300, 200, 300
Method client, "connect", .ip$, 80 As connect
=connect
}
}
=group(a)
}() // ("10") is ok
module inner {
? internet 'our global  using 142.250.187.100 which not working
? @internet ' original  - version 14 revision 7 return true, all other return false
}
Inner


The Inner module can call original internet using @. Global Grouo Internet { } not bypass then original Internet read only value, but using a simple global variable which get the group by a function do the job.


This module show how we can use a group to do the same job as internet$ do.

module testB {
global internet$="" ' need this to bypass the original internet$
function mockup(a$="100") {
group z$ {
ip$="142.250.187."+a$
value {
=" 0"
declare client client
With client, "NoError", True
Method client, "SetTimeouts", 100, 300, 200, 300
Method client, "connect", .ip$, 80 As connect
if connect then
declare HttpsRequest HTTPS.REQUEST
With HttpsRequest,"BodyFistLine" As RESP$
Method HttpsRequest, "HttpsRequest", "HTTPS://ifconfig.co/ip" As OK
if OK then =RESP$
end if
}
}
     =group(Z$)
}
global internet=mockup()
? internet$
let internet=mockup("10")
? internet$
list
}
testB
? internet$ ' this is the original



Πέμπτη 5 Φεβρουαρίου 2026

Ternary Logic

https://rosettacode.org/wiki/Ternary_logic#M2000_Interpreter 

Task
  • Define a new type that emulates ternary logic by storing data trits.
  • Given all the binary logic operators of the original programming language, reimplement these operators for the new Ternary logic type trit.
  • Generate a sampling of results using trit variables.


module Ternary_logic {
class trit {
private:
variant val
function copy() {
m=this
m.trit
=m
}
public:
enum ternary {
True="True"
Maybe="Maybe"
False="False"
}
function true() {
=.copy(.True)
}
function maybe() {
=.copy(.Maybe)
}
function false() {
=.copy(.False)
}
operator "==" (k as trit) {
push .val=k.val
}
operator "^^" (k as trit) {
select enum .val
case .True
.val<=k.val
case .False
.val<=.False
case else
if k.val=.False then .val<=.False else .val<=.Maybe
end select
}
operator "^|" (k as trit) {
select enum .val
case .True
.val<=k.val
case .False
.val<=.True
case else
if k.val=.True then .val<=.True else .val<=.Maybe
end select
}
operator "||" (k as trit) {
select enum .val
case .False
.val<=k.val
case .True
.val<=.True
case else
if k.val=.True then .val<=.True else .val<=.Maybe
end select
}
operator "~~" (k as trit) {
select enum .val
case .True
.val<=k.val
case .False
if k.val=.True then .val<=.False else.if k.val=.False then .val<=.True else .val<=k.val
case else
.val<=.Maybe
end select
}
operator unary {
select enum .val
case .True
.val<=.False
case .False
.val<=.True
end select
}
group value {
value {
link parent val to val
=val
}
}
module trit {
if empty or not isnum then
read s as .ternary=.Maybe
.val<=s
else.if isnum then
read what
if what then
.val<=.True
else
.val<=.False
end if
end if
}
}
function enum2array(t) {
m=each(t)
while m {data eval(m)}
=array([])
}
string out, nl={
}
q=trit()
m=trit()
k=enum2array(q.ternary)
out ="not a" + nl
a=each(k)
while a
q=trit(array(a))
z=-q
out +="    ternary_not "+(q.value) + " = " + (z.value) + nl
end while
out +="a and b" + nl
a=each(k)
while a
b=each(k)
while b
q=trit(array(a))
m=trit(array(b))
z=q ^^ m
out += "    " + (q.value) + " ternary_and " + (m.value) + " = " + (z.value) + nl
end while
end while
out +="a or b" + nl
a=each(k)
while a
b=each(k)
while b
q=trit(array(a))
m=trit(array(b))
z=q || m
out += "    " + (q.value) + " ternary_or " + (m.value) + " = " + (z.value) + nl
end while
end while
out +="if a then b" + nl
a=each(k)
while a
b=each(k)
while b
q=trit(array(a))
m=trit(array(b))
z=q ^| m
out += "    if " + (q.value) + " then " + (m.value) + " = " + (z.value) + nl
end while
end while
out +="a is equivalent to b" + nl
a=each(k)
while a
b=each(k)
while b
q=trit(array(a))
m=trit(array(b))
z=q ~~ m
out += "    "+(q.value) + " is equivalent to " + (m.value) + " = " + (z.value) + nl
end while
end while
report out
clipboard out
}
Ternary_logic

Output:

not a

    ternary_not True = False

    ternary_not Maybe = Maybe

    ternary_not False = True

a and b

    True ternary_and True = True

    True ternary_and Maybe = Maybe

    True ternary_and False = False

    Maybe ternary_and True = Maybe

    Maybe ternary_and Maybe = Maybe

    Maybe ternary_and False = False

    False ternary_and True = False

    False ternary_and Maybe = False

    False ternary_and False = False

a or b

    True ternary_or True = True

    True ternary_or Maybe = True

    True ternary_or False = True

    Maybe ternary_or True = True

    Maybe ternary_or Maybe = Maybe

    Maybe ternary_or False = Maybe

    False ternary_or True = True

    False ternary_or Maybe = Maybe

    False ternary_or False = False

if a then b

    if True then True = True

    if True then Maybe = Maybe

    if True then False = False

    if Maybe then True = True

    if Maybe then Maybe = Maybe

    if Maybe then False = Maybe

    if False then True = True

    if False then Maybe = True

    if False then False = True

a is equivalent to b

    True is equivalent to True = True

    True is equivalent to Maybe = Maybe

    True is equivalent to False = False

    Maybe is equivalent to True = Maybe

    Maybe is equivalent to Maybe = Maybe

    Maybe is equivalent to False = Maybe

    False is equivalent to True = False

    False is equivalent to Maybe = Maybe

    False is equivalent to False = True



Τετάρτη 21 Ιανουαρίου 2026

Array Length

https://rosettacode.org/wiki/Array_length#M2000_Interprete

Update using the three different objects for array: tuple, mArray, RefArray. Old versions of M2000 had only mArray, always as Variant (and tuple was mArray), then a RefArray used with squared brackets but using various item size from Byte, then mArray also drive a RefArray (using dimensions over RefArray - which the second object is hidden) so we may have A(10,2) as Byte, then tuple are an object always flat and for variants only. The B()=A when A point to tuple copies to B() as mArray. An mArray is heavier object, because holds array for one to ten dimensions of values for low and high bound, p;us an array for each dimension for offsets on a flat array (1d)  for item values (or pointer to RefArray, if we use specific type). A pointer to array may point to tuple or mArray. A pointer to RefArray can't change to anything else (can be value for a variant type variable or array item). A RefArray may have one or two dimensions, but we can construct any number by using a variant type RefArray using each item a refArray and so on. So we can make jagged arrays, using RefArrays. We can do the same using mArray of type variant or tuple. So A=((,), (1,), (1,2), (1,2,3)) is a jagged array of type tuple. The (,) is an empty tuple (length zero). For mArray arrays the A()=B() is a copy of B() to A(). and A()=A when A is pointer to mArray or tuple is also a copy, but A=B() is a pointer to B() copied to A.

' A is a pointer to array
A=("Apple", "Orange")
Print  Len(A)=2 ' True
Print Type$(A)="tuple"
Dim A(10,2) as Byte=32, B(), C(10,2)
Print Len(A())=20, Len(B())=0, Len(C())=20
C(1,1)="String"
C(2,0)=100, 3
Dim C(6,2)
Print Len(C())=12
Print C(2,0)=100, C(2,1)=3, C(1,1)="String"
B()=A ' this is a copy
A=(,)
Print B(1)="Orange", Len(B())=2, Len(A)=0
Print Type$(B())="mArray", Type$(A)="tuple"
A=B() ' now A point to B()
Print Type$(A)="mArray"
Print A(5,1)=32, Type$(A(5,1))="Byte"
A=A() ' point to A() we address through A as a flat 1d array.
Print Type$(A,0)="Byte", A#val(0)=32, A#sum()=32*20, A()#sum()=32*20
Print Dimension(A())=2 ' Number of dimensions
Print Dimension(A(), 1)=10, Dimension(A(), 2)=2 ' length for each dimension
Print Dimension(A(), 1, 0)=0, Dimension(A(), 1, 1)=9 ' lower and upper bound on 1st Dimension


' RefArray type of Arrays (always 0 lower bound)
Variant D[100]
Print Len(D)=101, Type$(D)="RefArray"
Byte F[9][1]
Print Len(F)=10
F[3][0]=111
F[3][4]=105
D[3]=F[3][] ' copy a row from F[3] to D[3]
F[3][0]++

Print D[3][0]=111, D[3][4]=105, F[3][0]=112