Lade...
 

Funktional Programmieren

Funktional Programmieren

InstantView®  unterstützt in gewissem Umfange auch einen funktionalen Programmierstil.

Motivation an Hand eines Beispiels:

Für alle Items (Klasse CX_ITEM) werden alle mit ihnen verbundenen Attribute (CX_ATTRIBUTE und abgeleitete) aufgesucht - VisitAttributes.
Die Operation mit den Attributen soll variabel sein.
Nicht funktionale Lösung: aufsammeln in einem Vektor. Der Vektor wird danach an den verarbeitenden Code weitergerecht.
Funktionale Lösung: Die Operation wird als Parameter übergeben und auf jedes Attribut sofort angewendet.

// Visit attributes of an attribute set Define(VisitAttrSet) LocalVar(action) -> action // action to perform on a single attribute Get(attributeSet) Dup if { Get(attributes) iterate { action Execute /* operate on this attribute now */ } } else Drop; // Visit attributes of all CX_ITEMS / CX_ITEM_PATTERNS Define(VisitAttributes) LocalVar(action) -> action // action to perform on a single attribute FindAll(CX_ITEM) iterate { LocalVar(item) -> item item action VisitAttrSet item Get(pattern) Dup if { action VisitAttrSet } else Drop };


Aufrufbeispiele:
- alle Attribute in einem ListView darstellen:

Define(TestDisplay) ({ UpdateObox(win, attributes) }) VisitAttributes;

 

- die Namen aller Attribute als Vektor aufsammeln:

Define(TestCollectNames) LocalVar(names) -> names ({ Copy(NameMA()) names Insert }) VisitAttributes // display names in a Text windowobject names StringVector("\n") PutValue(win, names);

 

{ } Block als anonyme Prozedur

 

({ statement1, statement2 , . . . statementn }) führt die Anweisungen nicht aus sondern legt eine anonyme Prozedur auf den Stack.

Das entspricht (fast)
Define(Foo) statement1, statement2 , . . .  statementn;  und (Foo)  -  die moderne Schreibweise für Push(Foo)
Natürlich können im Block wie in einer Procedure lokale Variablen deklariert und verwendet werden, das ist selbstverständlich.
Und doch gibt es einen kleinen Unterschied:

 

Closures
 

Im { } - Block sind auch die lokalen Variablen umhüllender Blöcke und der Procedure bekannt.
Wird die anonyme Prozedur vom Stack zu irgendeinem späteren Zeitpunkt mit Execute ausgeführt, halten diese Variablen den gleichen Wert, den sie bei bei sofortiger Ausführung, haben - also wie { statement1, statement2 , . . . statementn } ohne unschließende ( ).
Die Closure hält eine Referenz auf diese Varablen

 

Beispiel:

Define(TestClosure) LocalVar(x, f) 100 -> x ( { LocalVar(y) x /* this is a reference to the x ouside */ + -> y, y } ) -> f 41 -> x // this does change the code stored in variable f f SendMsg(RECEIVER) ;

und in einem anderen Modul: 

RECEIVER: -> f 1 f Execute // result is 42

    

Weiter Information zum Thema Closure: http://de.wikipedia.org/wiki/Closure

 


Anonyme Prozedur im Zugriffsausdruck

 

Im call-Term eines Zugriffsausdrucks wird eine InstantView®-Procedure über ihren Namen aufgerufen.
Aber es ist auch möglich, hier eine anonyme Prozedur anzugeben. Für kurze Code-Folgen spart man so eine separate Procedure-Definition mit der Vergabe eines Namens.
Beispiel:

 Define(Example)     LocalVar(factor, object)     3.67 -> factor     CreateTransObject(CX_EXPANDABLE) -> object     22.5m object Put(value)     object Copy(value.call({ LocalVar(val) -> val, val factor * }).Convert(\"mm\"))    ;    

 

Hier wird die im äußeren Scope definierte Variable factor benutzt.

Für die Zugriffsausdrücke innerhab einer Formats für ObjectListView und verwandte Widgets (siehe SetFormat) gibt es Einschränkungen:
 

  • call mit anonymer Prozedur darf nur innerhalb der Beschreibung mit Path benutzt werden, nicht wenn der Zugriffspfad im Format als String angebenen wird. (Die anonyme Prozedur muss vom InstantView®-Parser schon bem Parsen erkannt werden!)
  • Variablen aus einem äußeren Scope dürfen nicht referenziert werden (erzeugt Fehlermeldung beim Parsen).
    Diese Einschränkung ist notwendig, da der Zugriffsausdruck zu einem ganz anderen Zeitpunkt in einem anderen Kontext ausgewertet wird - nämlich beim Füllen des ListViews. Diesen Kontext "kennt" SetFormat nicht.