Τρίτη 23 Απριλίου 2019

Anonymous Functions

M2000 support anonymous functions with closures
If a closure is a reference type then saved as reference. So here s is a reference to a stack object. When we wish to use it, preserving items, we have to copy it, using stack() function ( stack(s,s) copy two times, in a new stack object)

Here f closure is a lambda function. A lambda function saved as closure as a value type, so each closure in a f is a new copy. So curry (a variable which hold the lambda function) get a function and all other arguments in a second closure, the stack object, and then return a lambda object. We make a new lambda named curried, which hold the anonymous function.

The disp variable hold another lambda, which we use it with a Call (without returning a result). By default if we use a numeric type lambda we get 0 if no return statement exist in function (we use = as statement to return value(s)).
We can store the lambda function (as a copy) to arrays and inventories (And stack objects, and lambda members of objects type of Group)

In M2000 a call to a function or module done without checking for proper arguments at the calling part. We can analyze the input before the use of arguments in code, but most times we use a Read statement, or the syntactic sugar the parameter list in parenthesis (which make a Read statement). Calling a function by Call we place current stack among the arguments, but using a function in an expression we use new stack with arguments only (can be expand, but at the exit from function the stack deleted).

Type checking are in two levels in M2000. First level, or basic level, is the two types, the numeric and the string type, for return type from expressions. So if we want a string type function we have to use $ in the name and for lambda functions we have to use lambda$ (and not lambda). A numeric type can return objects too. Also the string type may return objects too.

alfa$ =lambda$ ->{
        group k$ {
                k=1000
                value {
                        ="ok"
                }
        }
        =Group$(k)
}
Dim K$(10)
K$(3)=alfa$()
Print K$(3)
Link K$() to K()  ' so K() is a reference to K$()
Print K(3).k


Second level type checking is about the type of arguments. If we don;t provide type then type must be numeric/object or string/object depends of the name (like first level).
In sum function we have a loop while stack is not empty and we get  a number. If stack item isn't a number we get error.
change these lines to pass enum type arguments. We use the peek function, stackitem() which return numeric value even we have object, but we have to drop manual, using drop statement, to emulate a pop from stack.

sum=lambda -> {
        s=0   \\ number pop numbers from stack
        while not empty : s+=stackitem(): drop :end while
        =s
}
enum nums {five=5, seven=7, nine=9}
curried=curry(sum, five, seven, nine)


So in the example bellow we want numbers only (so we use Number which pop a number from stack)



\\ Anonymous Functions
curry=lambda (f)->{
        \\ get arguments as a stack object and store reference to s
        \\ f and s are closures to returned anonymous function
        =lambda f, s=[] -> {
                \\ pass arguments [] to f() if any
                \\ pass arguments using a copy of s
                \\ passing done using ! symbol before a stack object
                =f(![], !stack(s))
        }
}
sum=lambda -> {
        s=0   \\ number pop numbers from stack
        while not empty : s+=number:end while
        =s
}
curried=curry(sum, 5,7,9)
Print curried(1,2,3)=5+7+9+1+2+3  ' true
Print curried(10,20,30)=5+7+9+10+20+30 ' true
Print curried()=5+7+9  ' true
curried2=curry(sum)
Print curried2()=0
curried2=curry(sum, 10,20,30,40)
Print curried2(1,2,3,4)=110
\\ make a closure for a lambda function
disp=lambda title$="my title:" (that$) -> {
        Print title$;that$
}
Call disp("Anonymous Function")
Dim A(10)
A(3)=disp
ret=A(3)("Call from array")
Inventory Abc="100":=disp
ret=Abc("100")("Call from inventory")
ret=lambda title$="another tilte1:" (that$)->{Print title$;that$}("call anonymous function")
ret=lambda title$="another tilte2:" (that$)->{
        Print title$;that$
}("call anonymous function")

Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.