Remove two bugs, one from Type$(). Added const and final for lambdas.
const b=lambda->100
const b%=lambda->100
const b$=lambda$->"hello"
Print b%()
Print b$()
Try {
b=lambda->500
}
Print b()
Another addition for invoking lambda functions, using a hard link. All references by function (not by variable) to lambda use the old invoking method using a Call Extern Number, where number has the slot where the object (lambda object) exist.
When we make a lambda function, using a variable, interpreter make a function by same name and type (basic types), and from this revision make a hard link, and place empty code. So when we invoke the function, interpreter load code from lambda object, make all closures available to current name space (the scope of lambda), and after the end of execution get back to object all closures. From this revision, interpreter hold a reference to actual object, so if something change the object (if not const) in the slot, before the execution of lambda ends, then the object return to slot.
\\ this is in a global module A
group alfa {
x=100
b=lambda->{
=.x
.x++
}
}
\\ get a copy to alfa
beta=alfa
\\ try to change function with a fake one
function alfa.b {
=500
}
\\ references for functions are strings with code
\\ we get {CALL EXTERN 3}A.ALFA. (but is not the actual hard link.
\\ actual code is in lambda object. 3 is the actual "slot" where the object exist.
Print &alfa.b()
\\ we can make a link to f() (only for new identifiers)
Link alfa.b() to f()
Print f()
\\ this function can be changed because has no "hard link" with lambda
\\ all functions except final in groups can be changed
function f {
=500
}
Print f()=500
Print alfa.b()
Print beta.b()
\\ we can test pointers
\\ there is two type of pointers
\\ 1. pointers to float groups (holded in containers or by pointers)
\\ 2. pointer to named groups (using a weak reference)
\\ this type has no use when referenced group get out of scope
\\ but as all pointers can change value later
\\ pointers can be null, using p->0 but they hold just an empty group
\\ so never a pointer in M2000 has a real null value, but an "empty" one.
\\ p->(beta) is the same as this:
p=pointer((beta)) ' a copy of beta
Print p=>b(), p=>b()
Print beta.b()
\\ p->beta is same as this
p=pointer(beta) ' as reference to beta
Print p=>b(), p=>b()
So now is an example of recursion, closures, by value and by reference depends of the type of identifier. We can pass variables, array (with parenthesis by copy), pointers to containers as arrays (tuple), inventories (like map) and stacks (linked lists), groups (which are the user objects for OOP), other lambda functions, event objects, buffers (memory area). We can't pass ordinary functions and modules (but we can if they are in a group).
n=lambda ->500
a=lambda n (x)->{
if x<=0 then=0 : exit
=lambda(x-1)+x+n()
}
Print a(3)=1506
Print a(10)=5055
n=lambda->100
\\ closures are copies, and are like globals for lambda
Print a(3)=1506
\\ closures can be change only from inside
\\ if they are value types (lambda is a value type)
m=lambda->100
a=lambda n, m (x)->{
if x>5 then n=lambda ->500
if x<=0 then=0 : n=m : exit
=lambda(x-1)+x+n()
}
Print a(3)=306
Print a(10)=1055
\\ touple is an array, can have zero items (,)
\\ or one ore more, and it is a reference type
z=(m,)
Link z to Z()
Print Z(0)()=100
a=lambda z (x) -> {
if x<=0 then=0 : exit
link z to z()
=lambda(x-1)+x+z(0)()
}
\\ now we change value in z(0), which is the z
Print a(10)=1055
z(0)=lambda->300
\\ so now lambda change because hold a closure to a reference
Print a(10)=3055
Print eval(z)(0)()=300
\\ without using link we can get the first element in 0 posiiton, and ask for function
\\ this function has a life for the moment of call
\\ interpreter just open the lambda object, invoke, and close again.
a=lambda z (x) -> {
if x<=0 then=0 : exit
=lambda(x-1)+x+Eval(z)(0)()
}
Print a(10)=3055
Another one small example using pointers for groups.
class a {
counter as long
}
b=lambda k=pointer(a()) (x)-> {
k=>counter+=x
\\ we can return pointers from groups (if they are float type)
->k
}
m=b(30)
Print m=>counter=30
\\ get a pointer and convert it to a named group, and then return a float group (as is, without pointer)
def copy(x as group)=x
k=copy(b(300))
z->copy(b(300))
Print z=>counter=630
Print m=>counter=630
Print z is m ' false
z->b(300)
Print z is m 'true
Print z=>counter=930
Print k.counter=330 ' old value
The same as above but without using copy() user function
const b=lambda->100
const b%=lambda->100
const b$=lambda$->"hello"
Print b%()
Print b$()
Try {
b=lambda->500
}
Print b()
Another addition for invoking lambda functions, using a hard link. All references by function (not by variable) to lambda use the old invoking method using a Call Extern Number, where number has the slot where the object (lambda object) exist.
When we make a lambda function, using a variable, interpreter make a function by same name and type (basic types), and from this revision make a hard link, and place empty code. So when we invoke the function, interpreter load code from lambda object, make all closures available to current name space (the scope of lambda), and after the end of execution get back to object all closures. From this revision, interpreter hold a reference to actual object, so if something change the object (if not const) in the slot, before the execution of lambda ends, then the object return to slot.
\\ this is in a global module A
group alfa {
x=100
b=lambda->{
=.x
.x++
}
}
\\ get a copy to alfa
beta=alfa
\\ try to change function with a fake one
function alfa.b {
=500
}
\\ references for functions are strings with code
\\ we get {CALL EXTERN 3}A.ALFA. (but is not the actual hard link.
\\ actual code is in lambda object. 3 is the actual "slot" where the object exist.
Print &alfa.b()
\\ we can make a link to f() (only for new identifiers)
Link alfa.b() to f()
Print f()
\\ this function can be changed because has no "hard link" with lambda
\\ all functions except final in groups can be changed
function f {
=500
}
Print f()=500
Print alfa.b()
Print beta.b()
\\ we can test pointers
\\ there is two type of pointers
\\ 1. pointers to float groups (holded in containers or by pointers)
\\ 2. pointer to named groups (using a weak reference)
\\ this type has no use when referenced group get out of scope
\\ but as all pointers can change value later
\\ pointers can be null, using p->0 but they hold just an empty group
\\ so never a pointer in M2000 has a real null value, but an "empty" one.
\\ p->(beta) is the same as this:
p=pointer((beta)) ' a copy of beta
Print p=>b(), p=>b()
Print beta.b()
\\ p->beta is same as this
p=pointer(beta) ' as reference to beta
Print p=>b(), p=>b()
So now is an example of recursion, closures, by value and by reference depends of the type of identifier. We can pass variables, array (with parenthesis by copy), pointers to containers as arrays (tuple), inventories (like map) and stacks (linked lists), groups (which are the user objects for OOP), other lambda functions, event objects, buffers (memory area). We can't pass ordinary functions and modules (but we can if they are in a group).
n=lambda ->500
a=lambda n (x)->{
if x<=0 then=0 : exit
=lambda(x-1)+x+n()
}
Print a(3)=1506
Print a(10)=5055
n=lambda->100
\\ closures are copies, and are like globals for lambda
Print a(3)=1506
\\ closures can be change only from inside
\\ if they are value types (lambda is a value type)
m=lambda->100
a=lambda n, m (x)->{
if x>5 then n=lambda ->500
if x<=0 then=0 : n=m : exit
=lambda(x-1)+x+n()
}
Print a(3)=306
Print a(10)=1055
\\ touple is an array, can have zero items (,)
\\ or one ore more, and it is a reference type
z=(m,)
Link z to Z()
Print Z(0)()=100
a=lambda z (x) -> {
if x<=0 then=0 : exit
link z to z()
=lambda(x-1)+x+z(0)()
}
\\ now we change value in z(0), which is the z
Print a(10)=1055
z(0)=lambda->300
\\ so now lambda change because hold a closure to a reference
Print a(10)=3055
Print eval(z)(0)()=300
\\ without using link we can get the first element in 0 posiiton, and ask for function
\\ this function has a life for the moment of call
\\ interpreter just open the lambda object, invoke, and close again.
a=lambda z (x) -> {
if x<=0 then=0 : exit
=lambda(x-1)+x+Eval(z)(0)()
}
Print a(10)=3055
Another one small example using pointers for groups.
class a {
counter as long
}
b=lambda k=pointer(a()) (x)-> {
k=>counter+=x
\\ we can return pointers from groups (if they are float type)
->k
}
m=b(30)
Print m=>counter=30
\\ get a pointer and convert it to a named group, and then return a float group (as is, without pointer)
def copy(x as group)=x
k=copy(b(300))
z->copy(b(300))
Print z=>counter=630
Print m=>counter=630
Print z is m ' false
z->b(300)
Print z is m 'true
Print z=>counter=930
Print k.counter=330 ' old value
The same as above but without using copy() user function
class
a {
counter as long
}
b=lambda k=pointer(a()) (x)-> {
k=>counter+=x
->k
}
m=b(30)
Print m=>counter=30
group k=b(300)
z=b(300)
Print z=>counter=630
Print m=>counter=630
Print z is m ' false
z->b(300)
Print z is m 'true
Print z=>counter=930
Print k.counter=330 ' old value
counter as long
}
b=lambda k=pointer(a()) (x)-> {
k=>counter+=x
->k
}
m=b(30)
Print m=>counter=30
group k=b(300)
z=b(300)
Print z=>counter=630
Print m=>counter=630
Print z is m ' false
z->b(300)
Print z is m 'true
Print z=>counter=930
Print k.counter=330 ' old value
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
You can feel free to write any suggestion, or idea on the subject.