Programmierung (Packages)

Copyright

Copyright 1994,  Claudia Funke und Markus Herold
TU-Berlin, FB 13, Fachgebiet Ökonometrie und Statistik
Dieses Notebook darf ausschließlich als Unterrichtsmaterial und für private Zwecke verwendet und nicht ohne Zustimmung der Autorin verändert werden.

Packages

Das Ziel bemi Schreiben eines Packages ist es, die eigenen Funktionen
ähnlich den bereits in Mathematica vorhandenen Funktionen in das 
System zu integrieren.

Folgende Fehler können auftreten, wenn eigene Funktionen oder 
Definitionen innerhalb einer Mathematica-Session eingelesen werden:

- Variablen, die innerhalb eigener Definitionen verwendet werden, 
  wurden bereits innerhalb des Session definiert und mit Werten belegt.

- Variable werden als Funktionsargumente übergeben und gleichzeitig 
  innerhalb der eigenen Funktion lokal angewendet.

- Eine Funktion mit gleichem Namen wurde bereits definiert.

- Hilfsfunktionen oder Hilfsvariablen, die innerhalb eines Packages 
  verwendet werden, sind für den/die Anwendenden sichtbar und im 
  Zugriff. Damit besteht ein unkontrollierbar Zugriff auf die Funktions-
  implementierung.

Das folgende Beispiel demonstriert eines dieser Probleme. Dazu sei 
folgendes, selbst entwickeltes Mini-Package angenommen:

(* Package schlecht.m                              *)
(* Die Funktion berechnet die Potenzfunktion x^n.  *)
PowerSum[x_, n_] := Sum[x^i, {i, 1, n}]

Das Packages liegt als File vor und muß noch eingelesen werden.

<<schlecht.m

!!schlecht.m

PowerSum[x, 5]

PowerSum[i, 5]

Das obige Ergebnis ist unerwartet - für das Argument i sollte die 
Funktion ebenfalls einen symbolischen Ausdruck zurückgeben.

Lokale Variable

Um das obige Problem zu lösen, muß die Laufvariable  i   als    lokale 
Variable   definiert werden.

Das Mathematica-Konstrukt

deklariert die Variablen der Liste  variables  als lokal.

(* Package Besser.m *)                     

PowerSum::usage = 
"Die Funktion berechnet die Potenzfunktion x^n."
     
PowerSum[x_, n_] := 
     Module[{i},
        Sum[x^i, {i, 1, n}]
     ]

<<besser.m

PowerSum[i, 5]

Die erzeugten Variablen lassen sich anhand der (globalen) 
Symboltabelle anzeigen.

?Global`*

Die Variable  i   und die Laufvariable  i  werden nun als verschiedene 
Variablen behandelt. Allerdings sind die Variablen  i,  x  und n  noch 
außerhalb des Packages bekannt. Dies kann später zu Konflikten führen, 
wenn erneut auf diese Symbolnamen zurückgegriffen wird.

Kontext

Will man nun Variablen eines Packages von anderen innerhalb von 
Mathematica definierten Variablen trennen, benutzt man den 
Mechanismus des Kontexts.

Innerhalb eines Kontexts kann ein Variablenname oder Symbol nur 
einmal vergeben werden. Gleiche Variablennamen oder Symbole 
können aber in verschiedenen Kontexten definiert sein.

Alle Symbole haben standardmäßig den Kontext   Global`    .Die lokale 
Variable in der oben definierten Funktion PowerSum hat ebenfalls den 
Kontext Global. Dies wird durch die Einführung eines Kontext mit dem 
Namen   Private`   geändert.

Das neue Package hat damit folgende Form:

(* Package Gut.m *)                     

   PowerSum::usage = 
   "Die Funktion berechnet die Potenzfunktion x^n."
 
   Begin["Private`"]
     
   PowerSum[x_, n_] := 
      Module[{i},
         Sum[x^i, {i, 1, n}]
      ]   
 
   End[]

<<gut.m

?Global`*

Die lokale Variable   i   hat nun den Kontext   Private`   .Für 
Mathematica existiert diese Variable im Kontext Global` nicht und es 
kommt bei einer späteren Definition zu keinen Konflikten.

Durch die usage:: - Anweisung wird die Funktion nicht nur 
dokumentiert, sondern das Symbol  (hier: PowerSum)  wird gleichzeitig 
in den aktuellen Kontext gesetzt.

Ähnlich der $PATH-Varibale in Unix gibt die globale 
Mathematica-Variable $ContextPath    die Namen von Kontexten an, 
die Mathematica nach der Eingabe von Symbolen absucht. Wenn ein 
Package eingelesen wird, wird die $ContextVariable um diesen Kontext 
erweitert.

Nachdem alle lokalen Variablen und Funktionen verborgen wurden, 
sollten alle Funktionen, die das Package bereitstellt, in einen eigenen 
Kontext gestellt werden. Dieser Kontext muß innerhalb des Systems 
sichtbar sein, damit die Funktionen des Packages auch benutzt werden 
können. Dies geschieht durch die Befehle

.
      .
      .

Somit sieht das Package letztendlich folgendermaßen aus:

(* Package sehrgut.m *)                     
   BeginPackage["PowerSum`"]

   PowerSum::usage = 
   "Die Funktion berechnet die Potenzfunktion x^n."

   Begin["Private`"]
     
   PowerSum[x_, n_] := 
      Module[{i},
         Sum[x^i, {i, 1, n}]
      ]   
 
   End[]

   EndPackage[]

<<sehrgut.m

PowerSum[z, 4]

Context[PowerSum]

$ContextPath