Παρασκευή 1 Απριλίου 2016

M2000 First Class Functions (προσθήκη High Order Function) NEW

Ένα παράδειγμα για First Class Functions στην Μ2000.
Περιλαμβάνει μια λύση στο πρόβλημα που μπαίνει εδώ:
https://rosettacode.org/wiki/First-class_functions

Νέα Ανάρτηση:
Περιλαμβάνει την συνάρτηση λάμδα, οι ACOS και ASIN έχουν συλλάβει την RAD (captured).
Προστέθηκε και μια ακόμα περίπτωση με το Inventory (Κατάσταση). Σε μια λίστα μπήκαν και οι έξι συναρτήσεις και τις καλούμε με όνομα.(Η Κατάσταση δουλεύει με μοναδικά κλειδιά, γράμματα ή και αριθμούς)


\\ First-class functions
Print $("0.00")
RAD = lambda -> number/180*pi
ACOS = lambda RAD -> {
      Read x : x=Round(x,10)
      If x>=0 and x<1 Then {
            =RAD(2*Round(ATN(SQRT(1-x**2)/(1+x))) )
      }  Else.if x==1 Then {
            =0
      }  Else error "acos exit limit "
}
ASIN = lambda RAD -> {
    Read x : x=Round(x,10)
      If x>=0 and X<1 Then {
            =RAD(abs(2*Round(ATN(x/(1+SQRT(1-x**2))))))
      } Else.if x==1 Then {
            =RAD(90)
      } Else error "asin exit limit"
}
POW3 = Lambda ->number**3
POW3INV =Lambda ->number**(1/3)
COSRAD =lambda ->Cos(number*180/pi)
SINRAD=lambda ->SIN(number*180/pi)
'\ check
Print ACOS(COSRAD(.5)) , ASIN(SINRAD(.5)) , POW3INV(POW3(.5))
' \ pass a copy of each in array
Dim A(3), B(3)
A(0)=ACOS, ASIN, POW3INV
B(0)=COSRAD, SINRAD, POW3
For i=0 To 2 {
      Print A(i)(B(i)(.5)),
}
Print
Inventory func="ACOS":=ACOS,"ASIN":=ASIN,"POW3INV":=POW3INV
Append func,"COSRAD":=COSRAD,"SINRAD":=SINRAD,"POW3":=POW3
Print func("ACOS")(func("COSRAD")(.5)),
Print func("ASIN")(func("SINRAD")(.5)),
Print func("POW3INV")(func("POW3")(.5))





Παλιά Ανάρτηση:
Για να γίνει το παράδειγμα πρέπει να βάλω δυο συναρτήσεις που δεν έχει η Μ2000, τις ACOS και ASIN, τις οποίες τις βάζω για το πρόβλημα μόνο στο διάστημα 0,1. Επειδή τα COS, SIN και ATN στην Μ2000 δουλεύουν σε μοίρες θα κάνω τις μετατροπές όπου χρειάζονται. Αυτό συμβαίνει γιατί θέλουμε στο πρόβλημα να δώσουμε τιμή 0.5 σε ακτίνια για τα COS και SIN.

Το πρόβλημα ζητάει να γραφτεί μια Compose που να γυρνάει συνάρτηση. Οι συναρτήσεις είναι αλφαριθμητικά με ένα μπλοκ π.χ. αυτό είναι μια κενή συνάρτηση "{}" ή αυτό "{=100}" είναι αριθμητική συνάρτηση και γυρίζει το 100. Για να δουλέψει το αλφαριθμητικό ως συνάρτηση πρέπει να το δώσουμε στην εντολή Συνάρτηση() (αν θέλουμε αριθμητική τιμή, ή αντικείμενο ή πίνακα), ή Συνάρτηση$() αν θέλουμε αλφαριθμητική τιμή ή πίνακα αλφαριθμητικών ή συνάρτηση, ή με Κάλεσε π.χ. Κάλεσε "{Τύπωσε {Είμαι Συνάρτηση}}" αν δεν θέλουμε επιστροφή τιμής, ή να την καλέσουμε ως τμήμα (Module). Οι αγκύλες εκτός από μπλοκ εντολών στην Μ2000 έχουν και το ρόλο των εισαγωγικών. Έτσι στην Τύπωσε το {Είμαι Συνάρτηση} είναι αλφαριθμητικό. Έτσι και το {{=100}} είναι συνάρτηση εντός αλφαριθμητικού. Μπορούμε να βάζουμε μια Διάβασε να παίρνει παραμέτρους ή την Αριθμός για αριθμούς ή την Γράμμα$ για αλφαριθμητικά. Εδώ στο παράδειγμα χρησιμοποιώ την Number (δηλαδή την Αριθμός), αντί μια Διάβασε Χ

Στο τέλος έχω ένα συμπλήρωμα με ένα Group (Ομάδα, αντικείμενο της Μ2000), όπου περνάω μια συνάρτησή του σε ένα τμήμα και παράλληλα το "περιβάλλον της", δηλαδή μέσα στο τμήμα η συνάρτηση παρόλο που πήρε όνομα, έχει συνδεθεί με το αντικείμενο. Αυτό δεν γίνεται κατανοητό, από τα προηγούμενα, αφού έχουμε δει ότι το πέρασμα αναφοράς σε συνάρτηση περνάει τον ορισμό της. Αυτό που δεν φαίνεται είναι ότι μετά τον ορισμό της μπορούμε να περάσουμε το δείκτη του περιβάλλοντος. Και αυτό το κάνει ο διερμηνευτής επειδή για κάθε συνάρτηση κρατάει εκτός από όνομα και κώδικα και το δείκτη "περιβάλλοντος". (Οι δείκτες στην Μ2000 είναι αλφαριθμητικά, δεν δουλεύουμε εδώ με διευθύνσεις). Έτσι μέσα στο τμήμα Some2 αλλάζουμε την τιμή της ιδιότητας Ζ του αντικειμένου, χωρίς να πάμε το αντικείμενο εκεί, και ενώ η Ζ είναι ιδιωτική (δεν υπάρχει το Alfa.Z) και το βλέπουν μόνο συναρτήσεις/τμήματα του Αντικειμένου.


\\ First-class functions
Print $("0.00")
Function Global ACOS {
      Read x : x=Round(x,10)
      If x>=0 and x<1 Then {
            =2*Round(ATN(SQRT(1-x**2)/(1+x)))
      }  Else.if x==1 Then {
            =0
      }  Else error "acos exit limit "
}
Function Global ASIN{
    Read x : x=Round(x,10)
      If x>=0 and X<1 Then {
            =abs(2*Round(ATN(x/(1+SQRT(1-x**2)))))
      } Else.if x==1 Then {
            =90
      } Else error "asin exit limit"
}
\\ COS, SIN and ATN need Degree so we have To convert for example
Function Global DEG {=number*180/pi}
Function Global RAD {=number/180*pi}


Function Global POW3 {=number**3}
Function Global POW3INV {=number**(1/3)}
\\ check
Print RAD(ACOS(COS(DEG(.5)))) , RAD( ASIN(SIN(DEG(.5)))) , POW3INV(POW3(.5))


\\ using a compose function


Function Compose$ {
      Read A$, B$
      ="{=Function({"+B$+"}, Function({"+A$+"}, Number))}"
}
Link Weak Compose$("{=COS(DEG(number))}","{=RAD(ACOS(Number))}") To Combo1()
Link Weak Compose$("{=SIN(DEG(number))}","{=RAD(ASIN(Number))}") To Combo2()
Link Weak Compose$("{=POW3(Number)}","{=POW3INV(Number)}") To Combo3()
Print Combo1(.5), Combo2(.5), Combo3(.5)


Dim B$(3)
B$(0)=&Combo1(), &Combo2(),&Combo3()
For I=0 To 2
      Print Function(B$(I),0.5)
Next I


\\ or using a 2 dimension array
Dim A$(3,2)
\\ fill 0,0 Then 0,1 Then 1,0....
A$(0,0)="{=COS(DEG(number))}","{=RAD(ACOS(Number))}","{=SIN(DEG(number))}","{=RAD(ASIN(Number))}", "{=POW3(Number)}","{=POW3INV(Number)}"
\\ call using Function()
For I=0 To 2
      \\ print with or without compose function
      Print Function(A$(I,1), Function(A$(I,0),0.5)), Function(Compose$(A$(I,0), A$(I,1)), 0.5)
Next I
\\ call using linked names - (we can link again, for functions only)
For I=0 To 2
      Link Weak A$(I,0) To aName()
      Link Weak A$(I,1) To aNameInv()
      Print aNameInv(aName(.5))
Next I
\\ we can use local functions two
M=100
For this {
      \\ this is a temporary block
      Global M=10
      \\ one line function   is identical with Function One { Read X : = X+M }
      Def One(X)=X+M
      Def Two(X)=X-M
      Def Three(X)=X*5
      Print Function(Compose$(&One(),&Two()), .5)
      Print Function(Compose$(&One(),&Three()), .5) \\ 12.5
}
\\ now Global M and One(), Two(), Three() functions Erased...
Print M \\ 100


Module Some {
      Read &Func1(), &Func2(), &Func3()
      Print Func1(.5), Func2(.5), Func3(.5)
}
\\ call module Some passing functions
\\ reference for a function is copy of source
Some &Combo1(), &Combo2(), Compose$("{=POW3(Number)}","{=POW3INV(Number)}")



\\ Passing environment with function
Group Alfa {
Private:
      Z=100
Public:
      Function SetZ {
            Read .Z
      }
      Function GetZ {
            =.Z
      }
}


Module Some2 {
      Read &GetZZ()
      \\ here Alfa is not known
      Print Valid(Type$(Alfa)) \\ 0 not valid
      Call GetZZ(300) \\ call function without a return value
}
Some2 &Alfa.SetZ() \\ we pass function and  group environment
Print Alfa.GetZ() \\ now Z is 300
Print Valid(Type$(Alfa)) \\ -1 is valid




Πιο προχωρημένο θέμα με πέρασμα περιβάλλοντος (εδώ χωρίς χρήση αντικειμένου):

Let X=10, M=500
Function aLocalOne {
      Read New M
      X+=M
}
Module Some3 {
      Read &A()
      Call A(100)
}
\\ pass this enviroment
Some3 Lazy$(&aLocalOne())
Print X, M \\ 110, 500
\\ calling using this environment
Call Local aLocalOne(200)
Print X, M \\ 310,  500
\\ make a new function, return value using this environment
Link weak Lazy$((X+M)*Number) to AddBtoM()
Print AddBtoM(10) \\ 8100
M=1000
Module Some4 {
      Read &A()
      Print A(100) \\ 131000
}
\\ passing normal but has this environmet
Some4 &AddBtoM()
Link weak Lazy$(&aLocalOne()) to AnotherFunction()
Some3 &AnotherFunction()
Print X, M \\ 410, 1000




Μια προσθήκη όπου φαίνεται ο τρόπος να κληθεί μια ανώνυμη συνάρτηση.
Ουσιαστικά έχουμε ένα τρόπο να τρέξει η συνάρτηση από κώδικα.

Def A(x)=x^3
A$=&A()
Print Function(A$,3)
x=10
B$=Lazy$(A(20+x))
Print Function(B$) \\ 27000
x=0
Print Function(B$) \\  8000
X=10
C$="{Print x^3}" : Call Local C$
X++
Call Local "{Print x^3}"
X++
Inline "{Print x^3}"
X++
Print Function(Lazy$(x^3))



Εδώ δείχνουμε πως μπορούμε να κρατήσουμε αναφορά σε κώδικα και πως κώδικα.

Def A(X)=X^3 \\ same as X**3
\\ A$ points to A() using weak reference
A$=Lazy$(A(Number))
\\ B$ hold a copy of current A()
B$=&A()
\\ we change the function's code
Def A(X)=X*2
\\ A$ has lazy evaluation, so we call the new one
\\ B$ has function as value, so has the old one
Print Function(A$,10), Function(B$,10) '20  1000


Προσθήκη High Order Function με αντικείμενο.
Οι συναρτήσεις γυρνούν αντικείμενα που έχουν συναρτήσεις.
Εδώ η Compose παίρνει δυο συναρτήσεις (αντίγραφα κώδικα)
και τα βάζει σε δυο υποδοχείς Α$, Β$ και δίνει επιστροφή το αντικείμενο
Φτιάχνουμε το G από την Compose
Ακόμα και να χαθούν τα F() και Twice(), γιατί για παράδειγμα αυτός ο κώδικας είναι σε μια συνάρτηση ABC() και δίνουμε αυτό =G δηλαδή γυρνάμε το αντικείμενο, ο κώδικας των δυο συναρτήσεων είναι εντός του αντικειμένου σε μεταβλητές.

\\ Higher-Order Function
\\ no pointers - use of object
Function F {
      =Number+3
}
Function Twice {
      read &F()
      =F(F(Number))
}
Function Compose {
      Group AA {
            A$, B$
            Function Val {
                  =Function(.A$,.B$, number)
            }
      }
      Read AA.A$, AA.B$
      =AA
}
G=Compose(&Twice(),&F())
Print G.Val(7) \\ 13
Print G.Val(8) \\ 14





Χωρίς αντικείμενο, εδώ μάλιστα αλλάζω την F() για να φανεί ότι δεν έγινε αλλαγή, η παλιά F() υπάρχει στη g(). Στην ουσία φτιάχνουμε σε αλφαριθμητικό τον κώδικα της ανώνυμης συνάρτησης που θα επιστρέψει η Compose$()

\\ Higher-Order Function
\\ no pointers
Function F {
      =Number+3
}
Function Twice {
      read &F()
      =F(F(Number))
}
Def Compose$(f1$,f2$)="{=Function({"+f1$+"},{"+f2$+"}, number)}"
Link Weak Compose$(&Twice(),&F()) to g()
Function F {
      =Number+100
}
Print F(7) \\ 107
Print g(7) \\ 13
Print g(8) \\ 14



Παρακάτω έχουμε χρήση δεικτών. Η lazy$ φτιάχνει μια ανώνυμη μεν συνάρτηση με μια εντολή που της δίνει όνομα όταν τρέξει, το όνομα του τμήματος που χρησιμοποιήσαμε τη Lazy$. Δίνει αυτό "{ Module όνομάμου : = Twice(&F(),Number)}" δηλαδή δεν έχει κώδικα που τρέχει στο περιβάλλον που είναι η Twice και η F().

\\ Higher-Order Function
\\ this is a simulation
\\ because g() points to F()
Function F {
      =Number+3
}
Function Twice {
      read &F()
      =F(F(Number))
}
Link Weak Lazy$(Twice(&F(),Number)) to g()
Print g(7) \\ 13
Print g(8) \\ 14



Δείτε όμως πως μπορεί να δοθεί πίσω πριν τερματίσει το τμήμα:

\\ Higher-Order Function
g7=0
g8=0
Function Advance {
      \\ this is not a special function
      \\ is a part of this module
      \\ g7 and g8 are locals here
      \\ module Some call back Advance
      \\ passing back g()
      Read &g()
      \\ now g() is a High Order Function
      g7=g(7) \\ 13
      g8=g(8) \\ 14      
      \\ at the end of this part, g() erased
      \\ and any new variable/array/function
}

Module Some {
      Read &CallBack()
      Function F {
            =Number+3
      }
      Function Twice {
            read &F()
            =F(F(Number))
      }
      Link Weak Lazy$(Twice(&F(),Number)) to g()
      Call CallBack(&g())
}


Some Lazy$(&Advance())


Print g7 \\ 13
Print g8 \\ 14

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

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

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