Τετάρτη 16 Φεβρουαρίου 2022

Compose Functions

There are two kind of functions compositions. One kind is the lambda composition, the other use Eval() to evaluate a string as number and Eval$() to evaluate a string as string expression.


For the first kind, we have to make lambda functions. Lambda functions are first citizens, like variables we can pass them like values. Also a lambda function may have closures, and a lambda function can be a closure too.

Compose = lambda (f, g) ->{
=lambda f, g (x) ->f(g(x))
}
Ln1=lambda (x)->Ln(x)
Exp=lambda (x)->round(2.7182818284590452**x)
ExpLn=compose(Exp, Ln1)
Print ExpLn(3)


Compose$=lambda$ (f$, g$) ->{
=lambda$ f$, g$ (x$) ->f$(g$(x$))
}
Uc$=lambda$ (x$) ->Ucase$(x$)
Lc$=lambda$ (x$) ->Lcase$(x$)
UcLc$=Compose$(Uc$, Lc$)
Print UcLc$("GOOD")

For the second kind, we make two classes, one for handling the numeric functions and one for handling string functions. Also user functions have to be global to be used anywhere (and inside a method of an object too).

First we make class comp. There we have common parts for the other two "final" classes: 

  1. The Compose class for using one numeric parameter and two numeric functions.
  2. The ComposeStr$ class for using string parameter and two string functions

The ComposeStr$ has two names, the other name is ComposeStr without $. We have to use the second one if we want to use properties. M2000 for evaluation purposes need the $ character as last character for an identifier which return string value (or object which return string value). For this reason there are lambda$ (we see it before) and the class definition for an object which return string.\

An object (of generic type Group) return value if Value part exist. If the name of class/group has $ as last character then the Value part has to return a string. We can specify one or more parameters.

A property part is an object too. The difference is that we use at Value part the Value = expression, because automatic interpreter make a private variable, here a [formula]$ and from that variable fill the Value, so if we want to change that Value, we have to do in the Value { } part. The Property part has a Value and a Set part. Here the Set part not implemented, so property is read only. The same happen for classes Compose and ComposeStr$, we can define objects but we can't change them. We have to make the Set part.  If we place after value part in class Comp this: Set {read This}  we can change the object with a new Compose or ComposeStr$.

class Comp {
private:
composition$
public:
Property formula$ {
value {
link parent composition$ to c$
Value$=c$
}
}
}
class Compose as Comp {
value (x){
=Eval(.composition$)
}
Class:
module compose(a$, b$) {
.composition$<=a$+"("+b$+"(x))"
}
}
class ComposeStr$ as Comp {
value (x$){
=Eval$(.composition$.)
}
Class:
module composeStr(a$, b$) {
.composition$<=a$+"("+b$+"(x$))"
}
}
// example
function Global Exp(x) {
=round(2.7182818284590452**x)
}
ExpLog=Compose("Exp", "Ln")
Print ExpLog(3)
Print ExpLog.formula$
UcaseLcase$=ComposeStr$("Ucase$", "Lcase$")
Print UcaseLcase$("GOOD")
Print UcaseLcase.formula$


The modules Compose and ComposeStr, of classes Compose and ComposeStr$ aren't part of final objects, but are part at construction. Anything after the Class: label until another label (Public: or Private:) are only at construction (when we call the class). If we make a Group using Class: label, we can use multiple time the parts inside there but if we get a copy of group these aren't copy. This is the way the Class (as function) do. The constructor is the class name as module (without $ if we have ait on the class name). This module called in a different way, so anything we do there, not erased (but if those thing isn't part of the object, at the end of the class execution we get the object and anything else erased.

This is an example where we make a "bare" class alfa with a constructor. In the constructor we decide upon a parameter value which definition for group N we take and then we upgrade This with the group N. Property zeta is readonly property (but we can change the value inside object using the [zeta] (including [ ] characters). We have to use <= to assign new value, so in another module of alfa a statement like this (see the dot before the name) .[zeta]<=500 change the property zeta to value 500. If we ommit the {value} it is like we use this {value, set} so we can write and read the value of zeta. We don't do that except we wish to have code for value and set. We can have a simple variable zeta as public, for read and write from anywhere (inside and outside of an object).

class alfa {
class:
module alfa (x) {
if x>5 then
group N {
property zeta {value}=100
}
else
group N {
property zeta {value}=10
}
end if
this=N
}
}


M=alfa(2)
Print M.zeta=10
M=alfa(20)
Print M.zeta=100


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

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