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
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
You can feel free to write any suggestion, or idea on the subject.