Κυριακή, 10 Σεπτεμβρίου 2017

Using Lambda functions to get data

This is an example of creating a group Em as Function Employes() prepate (a Class in M2000 is a function to construct an object). As we see inside Em we have two inventories (lists with keys and data). In EmployId we put objects constructed with internal class Info. In Info class there is a Module Info after a Class: label. This means that this module exist only in first call (at construction). So a Info class create a group with two members, the N$ for Name and Salary for Salary.
We have two inventories, one for sorting names, and one for place info groups (objects in M2000). We use an id, as key in EmploId inventory, and Name as key in EmployName. In EmployName we put as data the id. So we can get from name the id.  (also we can get from id the name and the salary, from EmployId inventory).

We use Add module (in Em object) to add some names and salaries. So now we can pass lambda functions for searching and for display purposes.
Last lines show how to get copies of internal groups, by using name and how to get id by name

Flush
Class Employes {
      id=0
      Inventory EmployId, EmployName
      Class Info {
           N$, Salary
           Class:
           Module Info (.N$, .Salary) {}
      }
      Function NewId {
             .id++
             =.id
      }
      Module Add {
            If Match("SN") then {
                  emp=.Info(Letter$, Number)
                  id=.NewId()
                  Append .EmployId, id:=emp
                  Append .EmployName, emp.n$:=id
                  Sort ascending .EmployName as text
            }
      }
      Module ListAll {
            N=each(.EmployName)
            While N {
                  For This {
                        M=.EmployId(Eval(N))
                        Print  "[";Eval(N);"]", M.N$, M.Salary
                  }
            }
      }
      Function SelectSome {
            Read f \\ a lambda function
            Flush \\ empty stack
            N=each(.EmployId)
            While N {
                  For This {
                        M=Eval(N)
                        If f(&M) Then Data Eval$(N!) \\ put key to end of stack
                  }
            }
            =[] \\ return stack as object
      }
      Module ListIndirect {
            \\ using a stack object
            Read S
            If Match("F") Then {
                  Read f
            } else {
                  f=lambda (M, X)-> {
                        Print X, M.N$, M.Salary
                  }
            }
            N=Each(S)
            While N {
                        Call f(.EmployId(StackItem$(N)), N^+1)
            }
      }
      Property GetName {
            Value (name$) {
                  Link parent EmployName to EmployName
                  Link parent EmployId to EmployId
                  If exist(EmployName, name$) then {
                        Value=EmployId(Eval$(EmployName))
                  }          
            }
      }
      Property GetID {
                  Value (name$) {
                        Link parent EmployName to EmployName

                        If exist(EmployName, name$) then {
                              Value=val(Eval$(EmployName))
                        }    
                  }
            }
}
Em=Employes()
Em.Add "Peter", 3000
Em.Add "Susan", 2000
Em.Add "George", 1000
Em.ListAll
Print "Find all names with salary > 1000"
Em.ListIndirect Em.SelectSome(lambda (&M)->M.Salary>1000), lambda (m)->{Print m.N$}
\\ using default lambda inside ListIndirect
Em.ListIndirect Em.SelectSome(lambda (&M)->M.Salary>1000)

Print "Find all names with salary < 3000"
Print "Using Em.SelectSome and external Stack Object"
St=Em.SelectSome(lambda (&M)->M.Salary<3000)
D=Each(St)
While D {
      For Em.EmployId(StackItem$(D)) {
           Print .N$, .Salary
      }
}
Print "Using Em.ListIndirect and Em.SelectSome together"
Em.ListIndirect Em.SelectSome(lambda (&M)->M.Salary<3000), lambda (m)->{Print m.N$, m.Salary}

Print "Using GetName to get a copy of Employ Info"
Print Em.GetName("George").Salary, Em.GetName("George").N$
Print Em.GetName("Susan").Salary, Em.GetName("Susan").N$
Print "Using Em.GetId to get Id from name"
Print Em.GetId("Peter") \\ 1


We can get names through sorted inventory using alternate SelectSome:
Eval$(N) return data as string, so return key for .EmployId() which return group. Data command push to end - or bottom- of stack (Push command push in front or top of stack). [] is stack as object, which make two things, first return a pointer to stack, and second, place a new stack to current stack (here in this function). Functions have new stack when we call them through expression, but modules have parent stack as current stack.
For This { } open a block for temporary definitions. Here M is always a fresh variable, and after For This {} variable M deleted.
Symbol & before M means pass by reference. We can pass by reference any named variable (we can't pass by reference an item in a position in an array or in an inventory or in a stack object). Objects like array, inventory and stack can be passed by pointer, like passing by reference but not in every aspect. (if we change pointer by point to a new object then we "break" reference). This not happen with M which we pass it by Reference and every member of M passed by reference too. We can also pass only a member of M by reference.
Look f is a variable and read from stack an object, a lambda object. So at "read" interpreter make two things. Moving object from stack to variable f and making a new function f() to call this object. So when we call f(&M) interpreter pass &M as a weak reference to stack (its a string) and call f(), which call specific object. In lambda object, a read command make weak reference a normal reference to a new name, and execute code and then return true (-1) or false (0)
Because we want to use current stack as collection of selected employees. after reading the f (lambda function)  perform a Flush command which empty the stack. So if no employee founded, we return an empty Stack

Function SelectSome {
            Read f \\ a lambda function
            Flush \\ empty stack
            N=each(.EmployName)
            While N {
                  For This {
                        M=.EmployId(Eval$(N))
                        If f(&M) Then Data Eval$(N) \\ put key to end of stack
                  }
            }
            =[] \\ return stack as object
      }