Opal FAQ: Unterschied zwischen den Versionen
Kaufi (Diskussion | Beiträge) K (→Wichtige Strukturen) |
Milan (Diskussion | Beiträge) K |
||
(26 dazwischenliegende Versionen von einem anderen Benutzer werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
+ | {{historisch}} | ||
Vor noch nicht allzu langer Zeit, an einem nicht allzu weit entfernten Ort wurden einst alle Studis von einer schweren Programmiersprache dahingerafft ... | Vor noch nicht allzu langer Zeit, an einem nicht allzu weit entfernten Ort wurden einst alle Studis von einer schweren Programmiersprache dahingerafft ... | ||
Zeile 37: | Zeile 38: | ||
FUN meinPlus : nat ** nat -> nat | FUN meinPlus : nat ** nat -> nat | ||
</pre> | </pre> | ||
− | Hiermit wird eine Funktion <strong>deklariert</strong>, das Schlüsselwort <code>FUN</code> bedeutet, dass | + | Hiermit wird eine Funktion <strong>deklariert</strong>, das Schlüsselwort <code>FUN</code> bedeutet, dass an dieser Stelle eine Funktion angekündigt wird. Danach folgt der Name der Funktion (in diesem Fall meinPlus), nach dem Doppelpunkt folgt die Abbildung. Dies Funktion bildet zwei natürlichen Zahlen (<code>nat</code>) auf eine natürliche Zahl ab. Einfacher: die Funktion nimmt zwei Eingabewerte an und gibt einen Wert zurück und alle Werte haben denselben Typ. D.h. es dürfen nur (in diesem Fall) nur Zahlen angegeben werden. |
− | Hier endet die Signatur bereits, denn sie dient nur dazu anderen Strukturen zu zeigen was in der Struktur enthalten ist. Ähnlich einem Taschenrecher: aus der Taste seht ihr das Pluszeichen und wisst: dieser Taschenrechner kann addieren. Was ihr nicht wisst, ist <strong>wie</strong> intern addiert. Bei OPAL steht das in der Implementierung nach dem Begriff <code>DEF</code> für Definition. | + | Hier endet die Signatur bereits, denn sie dient nur dazu anderen Strukturen zu zeigen was in der Struktur enthalten ist. Ähnlich einem Taschenrecher: aus der Taste seht ihr das Pluszeichen und wisst: dieser Taschenrechner kann addieren. Was ihr nicht wisst, ist <strong>wie</strong> intern addiert wird. Bei OPAL steht das in der Implementierung nach dem Begriff <code>DEF</code> für Definition. |
===Wie sieht ein Funktions-Deklaration in OPAL aus?=== | ===Wie sieht ein Funktions-Deklaration in OPAL aus?=== | ||
Zeile 97: | Zeile 98: | ||
Die Funktion würde zu einem Fehler führen, denn das <code>THEN</code> würde nicht mehr interpretiert werden, weil ein Kommentarzeichen davor steht. | Die Funktion würde zu einem Fehler führen, denn das <code>THEN</code> würde nicht mehr interpretiert werden, weil ein Kommentarzeichen davor steht. | ||
− | + | == Wie konstruiert man eine Liste? == | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
Herzlichen dank für diesen Beitrag an Florian Lorenzen . | Herzlichen dank für diesen Beitrag an Florian Lorenzen . | ||
Zeile 304: | Zeile 206: | ||
nicht durch <>?(S) oder das Muster f(<>) angefangen werden kann, da S eindeutig nicht leer ist. | nicht durch <>?(S) oder das Muster f(<>) angefangen werden kann, da S eindeutig nicht leer ist. | ||
+ | |||
+ | == Benutzung des Interpreters oasys == | ||
+ | |||
+ | === Starten von oasys, Ausführen von Programmen === | ||
+ | Der OPAL-Interpreter <strong>oasys</strong> lässt sich von der Shell (auch Terminal oder Konsole) aus starten mit: | ||
+ | <pre> | ||
+ | oasys | ||
+ | </pre> | ||
+ | Um den Interpreter zu verlassen gibt man im Interpreter ein q für Quit ein: | ||
+ | <pre> | ||
+ | > q | ||
+ | </pre> | ||
+ | Hat man nun seine Dateien erstellt (z.B. Aufgabe1.impl und Aufgabe1.sign), muss man diese Dateien zuerst laden. Dafür muss man oasys in dem Verzeichnis starten, in dem die Dateien gespeichert sind. In welchem Verzeichnis ihr euch momentan befindet, erkennt ihr (meistens) an dem Verspann der Konsole. | ||
+ | <pre> | ||
+ | user@opalix ~/MPGI1/HA1/ $ | ||
+ | </pre> | ||
+ | Dieser Nutzer befindet sich, ausgehend von seinem Benutzerverzeichnis, im Verzeichnis MPGI1/HA/. Welche Dateien und Ordner sich noch in diesem Verzeichnis befinden, kann man mit dem Befehl <code>ls</code> oder <code>dir</code> herrausfinden. Mir dem Befehl <code>cd</code> kann das Verzeichnis gewechselt werden (in das übergeordnete Verzeichnis gelangt man bspw. mit der Angabe <code>cd ..</code>: | ||
+ | <pre> | ||
+ | user@opalix ~/MPGI1/HA1/ $ cd .. | ||
+ | user@opalix ~/MPGI1/ $ | ||
+ | </pre> | ||
+ | Also wechselt in das Verzeichnis wo sich die Dateien Aufgabe1.impl und Aufgabe1.sign beispielsweise befinden und starten von dort aus auf der shell den OPAL-Interpreter oasys. Wenn ihr oasys gestartet habt, könnt ihr das Verzeichnis nur wechseln, wenn ihr oasys vorher beendet (mit dem Befehl <code>q</code>), es ist jedoch ohne Probleme möglich eine weitere Shell zu öffnet und dort oasys in einem anderen Verzeichnis zu starten. | ||
+ | |||
+ | Als nächstes müssen die Dateien dem Interpreter zur Verfügung gestellt werden. Mit dem Interpreter-Befehl a (append file = Datei anfügen) lassen sich Dateien in den Interpreter laden. Dabei gibt man nur den Dateinamen ohne die Dateiendung an (bei langen Namen kann die <code>Tab</code>-Taste zur automatischen Vervollständigung genutzt werden, der Punkt am Ende ist egal). | ||
+ | <pre> | ||
+ | > a Aufgabe1 | ||
+ | loading Aufgabe1.impl | ||
+ | loading Aufgabe1.sign | ||
+ | > | ||
+ | </pre> | ||
+ | Wenn die Dateien erfolgreich geladen wurden wird das wie hier in dem Beispiel gezeigt quittiert. Außerdem erstellt oasys ein Verzeichis namens OCS. | ||
+ | |||
+ | Für oasys ist es notwendig, dass man zunächst den Fokus auf eine spezielle Datei legt. Dies erreicht man mit dem Befehl f (f für set focus). Wenn man die impl-Datei fokussiert, kann man auf alle Funktionen zugreifen die in dort implementiert wurden. So kann man aber unter Umständen vergessen eine vernüftige Signature (sign-Datei) zu schreiben und eine entsprechende Kapselung vorzunehmen (wichtig sobald mit mehr als einem Modul gearbeitet wird). Es ist gut sinnvolle Kapselung gleich mit zu lernen. | ||
+ | <pre> | ||
+ | > f Aufgabe1.impl | ||
+ | Aufgabe1.impl> | ||
+ | </pre> | ||
+ | oder: um zu testen welche Funktionen von außen erreichbar sind: | ||
+ | <pre> | ||
+ | > f Aufgabe1.sign | ||
+ | Aufgabe1.sign> | ||
+ | </pre> | ||
+ | Wenn das Fokussieren funktioniert hat, verändert sich eure Eingabe wie im Beispiel angegeben. | ||
+ | Um Funktionen auszuführen befehligt man oasys mit dem Befehl e (e für evaluate). Dabei wird aus der fokussierten Datei eine Funktion mit den Parametern die ihr in der Signatur festgelegt habt ausgewertet. Um diese vielen Begriffe zu verdeutlichen gehen wir mal davon aus, dass wir in der Datei eine Funktion add implementiert haben die zwei ganze Zahlen addiert. Diese Funktion ruft man dann so auf: | ||
+ | <pre> | ||
+ | Aufgabe1.impl>e add(1,2) | ||
+ | starting evaluator process | ||
+ | 3 | ||
+ | Aufgabe1.impl> | ||
+ | </pre> | ||
+ | |||
+ | === Eingabe von Zahlen, Denotations (Strings), Sequenzen und einzelne Buchstaben (Chars) === | ||
+ | |||
+ | Beispiel: | ||
+ | <pre> | ||
+ | > e funktionMitVielenArgumenten("lkajbblsd", "627849"!, 30,"c"!, %(1,23,9,1,8)) | ||
+ | </pre> | ||
+ | |||
+ | Erklärung: Das erste Argument ist eine Denotation, d.h. einfach ein String. | ||
+ | Die muss man einfach immer in Anführungszeichen setzen. :) | ||
+ | |||
+ | Das zweite ist eine Zahl. Da sie größer als 32 ist muss man sie als String hinschreiben (Anführungszeichen), den man dann mit dem Operator "!" in eine Zahl umwandeln kann. | ||
+ | |||
+ | Das dritte ist eine kleinere Zahl als 32, daher kann man sie direkt hinschreiben. | ||
+ | |||
+ | Das vierte ist ein Char, also ein einfacher Buchstabe. Da man das nicht direkt eingeben kann übergibt man Opal wieder einen String und wandelt ihn (da er nur einen Buchstaben enthält) mit dem "!" in einen Char um. | ||
+ | |||
+ | Das fünfte ist eine Sequenz, man kann sie direkt in dieser Form | ||
+ | hinschreiben, zu beachten gibt es nur ;) dass man so höchstens 8 Elemente verknüpfen kann. Will man mehr eingeben muss man eben 2 (oder noch mehr) dieser Dinger mit ++ verknüpft hinschreiben. | ||
+ | |||
+ | Diese Art Sequenzen zu schreiben eignet sich für Programmtests, wenn man sich die etwas umständliche Schreibweise sparen möchte. Wenn in einer Aufgabe der Umgang mit Listen geprüft werden soll, wird diese Schreibweise nicht empfohlen, da sie den rekursiven Aufbau der Liste verschleiert. Wenn eine Liste aber ähnlich einer Menge benutzt wird, ist die <code>%</code>-Schreibweise durchaus legitim. | ||
+ | |||
+ | Bsp: eine seq[nat] könnte man also so schreiben. | ||
+ | <pre> | ||
+ | %(4,3,5,8,2,21,5,5) ++ %(6,"78"!,"269"!,"987"!,"654"!,"321"!) | ||
+ | </pre> | ||
+ | |||
+ | Eine seq[seq[nat]] könnte man dann so schreiben | ||
+ | <pre> | ||
+ | %( %(1,3,2), %(1,2,3)) | ||
+ | </pre> | ||
+ | |||
+ | (man beachte die notwendige Umwandlung da die Zahlen zum Teil größer als 32 sind. :)) | ||
+ | |||
+ | (!!!) Vorsicht (!!!) man sollte im Normalfall keine Leerzeichen zwischen die Argumente setzen! Das funktioniert zwar meistens, leider aber nicht immer! | ||
+ | (Das gilt natürlich nur für die Kommandozeile, in den Syntax-Files selber sind Leerzeichen ziemlich wurscht. :)) | ||
+ | |||
+ | Also nochmal: Vorsicht vor Leerzeichen in Funktionsaufrufen! | ||
+ | |||
+ | Ich hatte schon Fehlermeldungen weil ich in Funktionen nach dem Komma ein Leerzeichen eingebaut hatte. | ||
+ | |||
+ | Bsp: func1("9023"!, "0234"!) | ||
+ | |||
+ | Lässt man das weg, funktionierte (bisher) alles: | ||
+ | <pre> | ||
+ | func1("9023"!,"0234"!) | ||
+ | </pre> | ||
+ | |||
+ | Speziell wenn man Texte in Nummern umwandelt (siehe oben) scheint das zu Problemen zu führen. (Dieses Problem hatte ich selbst bisher nur wenn ich von der Shell (Kommandozeile aus direkt Argumente in eine Funktion füttern wollte. Ansonsten trat es nicht auf. :) | ||
=== Oasys an der Shell herumkommandieren: === | === Oasys an der Shell herumkommandieren: === | ||
+ | |||
Herzlichen Dank an Roman Lechtchinsky | Herzlichen Dank an Roman Lechtchinsky | ||
Zeile 332: | Zeile 334: | ||
</pre> | </pre> | ||
− | ==Fehler / Probleme mit OPAL == | + | ==Fehler/Probleme mit OPAL == |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
=== Warum funktionieren Zahlen über 32 nicht? === | === Warum funktionieren Zahlen über 32 nicht? === | ||
Zeile 362: | Zeile 346: | ||
Die Zahlen von <code>0</code>-<code>32</code>, die Zweierpotenzen <code>64,128,256,512,1024</code> und die Zahlen <code>100, 1000, 10000, 100000, 1000000</code>. Daneben gibt es noch die Konstanten <code>pi</code> und <code>e</code> für die ludolfsche Zahl (Pi) und die eulersche Zahl. | Die Zahlen von <code>0</code>-<code>32</code>, die Zweierpotenzen <code>64,128,256,512,1024</code> und die Zahlen <code>100, 1000, 10000, 100000, 1000000</code>. Daneben gibt es noch die Konstanten <code>pi</code> und <code>e</code> für die ludolfsche Zahl (Pi) und die eulersche Zahl. | ||
− | ===Warum funktionieren (manchmal) auch Zahlen unter 32 nicht?=== | + | === Warum funktionieren (manchmal) auch Zahlen unter 32 nicht? === |
Dies ist meistens der Fall, wenn das Programm mit oasys über die Signatur aufgerufen wird. In der Signatur werden meistens nur die Sorten (bspw. <code>nat</code>, <code>denotation</code>) importiert, da Zahlen auch Funktionen sind, müsste man diese auch importieren. Etwas flexibler ist es, die Umwandlungsfunktion <code>!</code> zu importieren. Dann müssen zwar alle Zahlen erst von einer Zeichenkette umgewandelt werden, aber so kann man überhaupt mit Zahlen arbeiten: | Dies ist meistens der Fall, wenn das Programm mit oasys über die Signatur aufgerufen wird. In der Signatur werden meistens nur die Sorten (bspw. <code>nat</code>, <code>denotation</code>) importiert, da Zahlen auch Funktionen sind, müsste man diese auch importieren. Etwas flexibler ist es, die Umwandlungsfunktion <code>!</code> zu importieren. Dann müssen zwar alle Zahlen erst von einer Zeichenkette umgewandelt werden, aber so kann man überhaupt mit Zahlen arbeiten: | ||
Zeile 370: | Zeile 354: | ||
Natürlich kann man auch <code>COMPLETELY</code> statt <code>ONLY</code> benutzen. Dies wird aber teilweise als schlechter Stil empfunden. | Natürlich kann man auch <code>COMPLETELY</code> statt <code>ONLY</code> benutzen. Dies wird aber teilweise als schlechter Stil empfunden. | ||
− | ===Warum | + | === Warum funktionieren Kommazahlen nicht? === |
+ | Zuallererst: Kommazahlen werden in Opal mit einem Punkt notiert, bspw. ist <code>3,14159</code> in Opal <code>3.14159</code>. | ||
− | + | Wie bei der [[#Warum_funktionieren_Zahlen_.C3.BCber_32_nicht.3F | Frage zu Zahlen über 32]] bereits beschrieben, müssten gleich benutzbare Zahlen als (konstante) Funktion in einer Struktur definiert (und deklariert) sein. Das ist nicht der Fall (außer bei <code>pi</code> und <code>e</code>). Der Standardfehler den <code>oasys</code> in diesem Fall ausgibt ist: | |
+ | <pre> | ||
+ | ERROR [at ...] no matching operation for . | ||
+ | ERROR [check] language error | ||
+ | </pre> | ||
− | === | + | <code>oasys</code> hält also das Komma (den Punkt) für eine (binäre) Funktion. Um Kommazahlen in Opal zu benutzen, müssen sie "kontruiert" werden. Hierfür enthalten Strukturen, die Kommazahlen nutzen, die Funktion <code>!</code>. Kommazahlen werden also als Denotation geschrieben: "<code>3,14159</code>" und dann mit der (unären) Funktion <code>!</code> umgewandelt: !"<code>3,14159</code>" oder "<code>3,14159</code>"!, inbesondere bei der Nutzung in längeren Gleichungen oder der oasys-Eingabe kann dieses Ausrufezeichen (da unär) schon einmal für unerwartete Fehler sorgen (mehr dazu [[#Was_ist_Pr.C3.A4fix-.2C_Infix-_und_Postfixnotation.3F|Was ist Präfix-, Infix- und Postfix-Notation?]]). |
+ | |||
+ | === Warum kann man Denotations immer nutzen und Zahlen nicht? === | ||
+ | |||
+ | Wenn eine OPAL-Struktur interpretiert (und später übersetzt) wird, lädt der Interpreter bestimmte Strukturen automatisch. Diese heißen bspw. <code>BOOL</code> und <code>DENOTATION</code> und stellen elementare Funktionen zur Verfügung. Deshalb kann man ohne den Import von irgendwelchen Strukturen IF-THEN-ELSE-Konstrukte in OPAL nutzen und mit Denotations arbeiten (nicht aber mit Zahlen, denn die werden nicht automatisch importiert). Die in der Schreibung ähnlichen Strukturen <code>Bool</code> und <code>Denotation</code> stellen aber noch weitere Funktionen zur Verfügung, deshalb müssen sie gelegentlich doch importiert werden. | ||
+ | |||
+ | === Warum wird meine Backtick-Funktion (`) nicht benutzt? === | ||
Die Backtick-Funktion für eigene Datentypen muss in der .sign-Datei mit deklariert sein. | Die Backtick-Funktion für eigene Datentypen muss in der .sign-Datei mit deklariert sein. | ||
+ | |||
+ | |||
+ | === Warum funktioniert WHERE nicht ohne weiteres mit Lambda-Ausdrücken? === | ||
+ | |||
+ | Wenn man Lambda mit WHERE kombinieren will muss man den ganzen Body der Funktion klammern | ||
+ | |||
+ | Das geht so: | ||
+ | <pre> | ||
+ | DEF qsolve1 == \\ a, b, c .( /* <--- */ | ||
+ | (x1, x2) | ||
+ | WHERE | ||
+ | x1 == (-(b) + d) / (2 * a) | ||
+ | x2 == (-(b) - d) / (2 * a) | ||
+ | d == sqrt((b * b) - (4 * a * c)) | ||
+ | |||
+ | ) /* <----- */ | ||
+ | </pre> | ||
+ | |||
+ | Wichtig ist dabei, dass nach dem Punkt, mit dem der Lambda Ausdruck die Argumentliste abschließt, kein Leerzeichen oder irgendetwas anderes ist, sondern gleich die öffnende Klammer kommt. Ansonsten funktioniert es nicht! | ||
+ | |||
+ | |||
=== Häufige Fehlermeldungen === | === Häufige Fehlermeldungen === | ||
Zeile 406: | Zeile 422: | ||
Es müsste ein < oder > durch <= bzw. >= ersetzt werden, oder der Fall = explizit aufgeführt werden. | Es müsste ein < oder > durch <= bzw. >= ersetzt werden, oder der Fall = explizit aufgeführt werden. | ||
− | === | + | ==== ambigious infix application ==== |
− | |||
+ | Dieser Fehler deutet darauf hin, dass bei Infix-Notation die Klammern nicht eindeutig gesetzt werden konnten. Ein Beispiel sind die logischen Funktionen <code>/\</code> (und) und <code>\/</code> (oder). Opal hat hierfür keine Klammerregelung, der Ausdruck | ||
+ | <pre> | ||
+ | false /\ true \/ true | ||
+ | </pre> | ||
+ | kann auf zwei Arten geklammert werden: entweder <code>'''('''false /\ true''')''' \/ true</code> (ausgewertet zu true) oder <code>false /\ '''('''true \/ true''')'''</code> (ausgewertet zu false). | ||
− | + | === Was ist Präfix-, Infix- und Postfixnotation? === | |
+ | ...oder wie man Minuszeichen hassen lernt. | ||
+ | |||
+ | Bei der '''Präfix'''-Notation wird der Funktionsname vor den Argumenten geschrieben, bspw. <code>!"33"</code>, oder +(3,5). Bei Funktionen mit mehr als einem Parameter müssen die Argumente in Klammern gesetzt und durch Kommas getrennt werden. | ||
+ | |||
+ | Die '''Infix'''-Notation ist nur bei zweistelligen (oder binären) Funktionen möglich (also Funktionen mit genau zwei Parametern). Beispiele dafür sind die Funktionen <code>+, /\, *,</code> usw.: | ||
+ | <pre> | ||
+ | 5 + 6 | ||
+ | true /\ false | ||
+ | 4 * 6 | ||
+ | </pre> | ||
+ | Bei den meisten zweistelligen Funktione sind auch solche Konstruktionen möglich: <code>3 + 4 + 9 + 2</code>, die Klammerung wird implizit vorgenommen, auch Mischungen wie <code>3 + 4 * 7 + 3</code> werden den mathematischen Gesetzen entsprechend geklammert. | ||
+ | |||
+ | Die '''Postfix'''-Notation ähnelt der Präfix-Notation, nur dass hier hier der Funktionsname nach den Parametern notiert wird. Bspw. <code>"33"!</code> oder <code>(6,3)-</code>. | ||
+ | |||
+ | Insbesondere bei einstelligen (unären) Funktionen, wie <code>!</code>, oder <code>-</code> (als Vorzeichen), kommt es öfter zu solchen Fehlermeldungen: | ||
<pre> | <pre> | ||
Zeile 504: | Zeile 539: | ||
Im Grunde das gleiche wie vorher, siehe [[Opalix 2007#Fehler:_Operation_not_permitted|Opalix-Seite]]. | Im Grunde das gleiche wie vorher, siehe [[Opalix 2007#Fehler:_Operation_not_permitted|Opalix-Seite]]. | ||
− | === Fehler in Zeile | + | === Was bedeutet ein Fehler in Zeile 0? === |
Bei einem ansonsten korrekten Programm hat mich diese Fehlermeldung vorhin eine laaange Fehlerjagd gekostet... | Bei einem ansonsten korrekten Programm hat mich diese Fehlermeldung vorhin eine laaange Fehlerjagd gekostet... | ||
Zeile 510: | Zeile 545: | ||
<pre> | <pre> | ||
Person.impl>e Birthday(date(30,12,"79"!) | Person.impl>e Birthday(date(30,12,"79"!) | ||
− | ERROR [at | + | ERROR [at 0.3-0.4]: Expected was `)' instead of `IN' |
ERROR [check]: language error | ERROR [check]: language error | ||
aborted | aborted | ||
Zeile 517: | Zeile 552: | ||
In diesem Fall hatte ich auf der Eingebe-Zeile im Interpreter eine schließende Klammer vergessen. :)) | In diesem Fall hatte ich auf der Eingebe-Zeile im Interpreter eine schließende Klammer vergessen. :)) | ||
− | Man kann diese Fehler recht leicht erkennen. Sie finden immer auf Zeile | + | Man kann diese Fehler recht leicht erkennen. Sie finden immer auf Zeile '''0''' statt. Das ist die Eingabe-Zeile in der Shell. :)) |
− | (" ERROR [at | + | (" ERROR [at 0.3-0.4]:") |
+ | |||
+ | Der Fehler muss folglich auch nicht immer ein Syntax-Fehler sein (wie oben), sondern kann auch durch die Sprache in der die Eingabe von <code>oasys</code> programmiert ist hervorgerufen werden (siehe [[#Oasys_an_der_Shell_herumkommandieren: | Oasys an der Shell herumkommandieren]]). | ||
=== Nicht nachvollziehbare Laufzeitfehler === | === Nicht nachvollziehbare Laufzeitfehler === | ||
Zeile 665: | Zeile 702: | ||
|- | |- | ||
| [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/NatConv.html#SEC98 NatConv] | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/NatConv.html#SEC98 NatConv] | ||
− | | Stellt Funktionen zur Umwandlung in andere Typen bereit | + | | Stellt Funktionen zur Umwandlung von natürlichen Zahlen in andere Typen bereit |
| asChar, asInt, asReal, ` | | asChar, asInt, asReal, ` | ||
|- | |- | ||
Zeile 673: | Zeile 710: | ||
|- | |- | ||
| [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/RealConv.html#SEC100 RealConv] | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/RealConv.html#SEC100 RealConv] | ||
− | | Stellt Funktionen zur Umwandlung in andere Typen bereit | + | | Stellt Funktionen zur Umwandlung von reellen Zahlen in andere Typen bereit |
| asNat, asInt, `, `` | | asNat, asInt, `, `` | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Int.html#SEC75 Int] | ||
+ | | Stellt Funktionen und Sorten der ganzen Zahlen bereit | ||
+ | | +,-,*,div,mod | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/IntConv.html#SEC96 IntConv] | ||
+ | | Stellt Funktionen zur Umwandlung von reellen Zahlen in andere Typen bereit | ||
+ | | asNat, asReal, ` | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Bool.html#SEC24 Bool] | ||
+ | | Stellt Funtionen und Sorten für boolsche Ausdrücke zur Verfügung | ||
+ | | /\, \/, => | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/BoolConv.html#SEC30 BoolConv] | ||
+ | | Stellt eine Funktion zur Umwandlung von Wahrheitswerten (true/false) in Text zu Verfügung | ||
+ | | nur ` | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Char.html#SEC48 Char] | ||
+ | | Stellt Funktionen für Buchstaben und Zeichen/Eingaben zur Verfügung | ||
+ | | pred, newline, lower?, whitespace? | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/CharConv.html#SEC61 CharConv] | ||
+ | | Stellt Funktionen zur Umwandlung von Buchstaben/Zeichen zur Verfügung | ||
+ | | `, asNat, asDigitNat | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Denotation.html#SEC50 Denotation] | ||
+ | | Stellt Funktionen für Textverarbeitung zur Verfügung | ||
+ | | #, slice, empty? | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/String.html#SEC287 String] | ||
+ | | Stellt Funktion für dynamische Textverarbeitung bereit | ||
+ | | #, empty?, ++, % | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/StringConv.html#SEC301 StringConv] | ||
+ | | Stellt Funktionen zur Umwandlung von Zeichenketten bereit | ||
+ | | asSeq, asString, ` | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Seq.html#SEC215 Seq] | ||
+ | | Stellt Grundfunktionen für die Arbeit mit Listen zur Verfügung | ||
+ | | <>, ::, exist?, % | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/SeqConv.html#SEC229 SeqConv] | ||
+ | | Stellt eine Grundfunktion zur Umwandlung von Listen bereit | ||
+ | | nur ` | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/SeqFilter.html#SEC231 SeqFilter] | ||
+ | | Stellt eine Filterfunktion auf Listen zzgl. Hilfsfunktionen zur Verfügung | ||
+ | | filter, partition, split | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/SeqMap.html#SEC240 SeqMap] | ||
+ | | Enthält eine Funktion zur Umwandlung von Listen | ||
+ | | nur map oder * | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/SeqReduce.html#SEC247 SeqReduce] | ||
+ | | Stellt Funktionen zur Reduktion von Listen bereit | ||
+ | | reduce oder /, \ | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/SeqZip.html#SEC255 SeqZip] | ||
+ | | Stellt Funktionen zum Zusammenfügen und Zertrennen von Listen zur Verfügung | ||
+ | | zip, unzip | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Option.html#SEC189 Option] | ||
+ | | Stellt einen Zugriffstyp und Zugriffsfunktionen für Datentypen zur Verfügung | ||
+ | | cont, <, = | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Compose.html#SEC109 Compose] | ||
+ | | Stellt Funktionen zur Komposition von Funktionen bereit | ||
+ | | o, ; | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Tree.html#SEC325 Tree] | ||
+ | | Stellt Grundfunktionen zur Arbeit mit Bäumen zur Verfügung | ||
+ | | lrotate, %, # | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/TreeConv.html#SEC368 TreeConv] | ||
+ | | Stellt Funktionen zur visuell ansprechenden Ausgabe von Bäumen bereit | ||
+ | | asSeqIn, `, graphic | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Com.html#SEC844 Com] | ||
+ | | Stellt Grundfunktionen für die Behandlung von Monaden bereit | ||
+ | | succeed, yield, break | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/ComCompose.html#SEC846 ComCompose] | ||
+ | | Funktionen zur Komposition von Monaden | ||
+ | | &, ; | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/BasicIO.html#SEC915 BasicIO] | ||
+ | | Stellt Grundfunktionen für Ein- und Ausgabe bereit | ||
+ | | ask, writeLine, write | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/File.html#SEC943 File] | ||
+ | | Stellt Funktionen für den Dateizugriff zu Verfügung | ||
+ | | open, reopen, close | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Void.html#SEC36 Void] | ||
+ | | Stellt einen leeren Datentyp bereit (wichtig für Monaden) | ||
+ | | nur void (Datentyp) | ||
|} | |} | ||
Außerdem stellt OPAL die Struktur [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Basics.html#IDX201 Basics] zur Verfügung, diese lädt automatisch folgende Strukturen: | Außerdem stellt OPAL die Struktur [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Basics.html#IDX201 Basics] zur Verfügung, diese lädt automatisch folgende Strukturen: | ||
Zeile 691: | Zeile 824: | ||
[http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Real.html#SEC88 Real], | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Real.html#SEC88 Real], | ||
[http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/RealConv.html#SEC100 RealConv]. | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/RealConv.html#SEC100 RealConv]. | ||
+ | |||
+ | '''Hinweis:''' Einige Strukturen importieren bereits andere, die Einzelheiten finden sich in der Referenz. | ||
===Interessante Strukturen=== | ===Interessante Strukturen=== | ||
− | <strong>Anmerkung:</strong> | + | <strong>Anmerkung:</strong> Diese Strukturen werden im Studium nicht zwingend behandelt, enthalten aber interessante Zusatzinformationen und erleichtern die Arbeit, wenn man über die Studieninhalte hinaus mit OPAL experimentieren möchte. Einige Strukturen sind auch hilfreich bei der sinnvollen Strukturierung von eigenen Strukturen (auch bei Hausaufgaben). |
+ | |||
{| class="wikitable sortable" | {| class="wikitable sortable" | ||
! Name !! class="unsortable" style="text-align:left" | Inhalt !! class="unsortable" style="text-align:left" | Auswahl von Funktionen | ! Name !! class="unsortable" style="text-align:left" | Inhalt !! class="unsortable" style="text-align:left" | Auswahl von Funktionen | ||
Zeile 700: | Zeile 836: | ||
| Lässt eigene Fehlerbehandlungstexte zu | | Lässt eigene Fehlerbehandlungstexte zu | ||
| nur ABORT | | nur ABORT | ||
+ | |- | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Set.html#SEC482 Set] | ||
+ | | Struktur die Funktionen und Typen auf Mengen enthält | ||
+ | | {}, incl, forall? | ||
|} | |} | ||
===Wichtige Funktionen=== | ===Wichtige Funktionen=== | ||
+ | '''Anmerkung:''' Funktionen mit demselben Namen verhalten sich in verschiedenen Strukturen ähnlich (Prinzip der Orthogonalität). Einige Funktionen heißen aber auch gleich und machen völlig verschiedene Dinge. Für viele Funktionen gibt es mehrere Namen. | ||
{| class="wikitable sortable" | {| class="wikitable sortable" | ||
− | ! Name !! class="unsortable" style="text-align:left" | Beschreibung !! | enthalten in | + | ! Name !! class="unsortable" style="text-align:left" | weitere Namen !! class="unsortable" style="text-align:left" | Beschreibung !! class="unsortable" style="text-align:left" | enthalten in |
|- | |- | ||
+ | | div | ||
| / | | / | ||
− | | | + | | Divisions-Operator (für ganze Zahlen) |
− | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Nat.html#IDX1225 Nat] | + | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Nat.html#IDX1225 Nat], [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Int.html#SEC75 Int] |
+ | |- | ||
+ | | mod | ||
+ | | % | ||
+ | | Rest der ganzzahligen Division | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Nat.html#IDX1225 Nat], [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Int.html#SEC75 Int] | ||
|- | |- | ||
| / | | / | ||
− | | | + | | keine |
− | |[http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Real.html# | + | | Divisionsoperator |
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Real.html#SEC88 Real] | ||
+ | |- | ||
+ | | pow | ||
+ | | ^ | ||
+ | | Potenzfunktion | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Nat.html#IDX1225 Nat], [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Int.html#SEC75 Int], [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Real.html#SEC88 Real] | ||
+ | |- | ||
+ | | ++ | ||
+ | | keine | ||
+ | | Konkatenation von Werten | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Denotation.html#SEC50 Denotation], [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/String.html#SEC287 String], [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Seq.html#SEC215 Seq] | ||
+ | |- | ||
+ | | even? | ||
+ | | keine | ||
+ | | Gibt an, ob eine Zahle gerade ist | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Nat.html#IDX1225 Nat], [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Int.html#SEC75 Int] | ||
+ | |- | ||
+ | | odd? | ||
+ | | keine | ||
+ | | Gibt an, ob eine Zahl ungerade ist | ||
+ | | [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Nat.html#IDX1225 Nat], [http://projects.uebb.tu-berlin.de/opal/dosfop/2.4a/bibopalicaman/Int.html#SEC75 Int] | ||
|} | |} | ||
Zeile 744: | Zeile 912: | ||
| Führe das Kommando (die Funktion) aus | | Führe das Kommando (die Funktion) aus | ||
| <code>x meineMonadenFunktion</code> | | <code>x meineMonadenFunktion</code> | ||
+ | |- | ||
+ | | r | ||
+ | | reload | ||
+ | | Erzwingt das Neuladen von veränderten Strukturen | ||
+ | | <code>r</code> ohne Argument | ||
|- | |- | ||
| l, ll | | l, ll |
Aktuelle Version vom 12. März 2024, 15:27 Uhr
Dieser Artikel spiegelt sehr wahrscheinlich nicht mehr den aktuellen Stand wider, könnte aber trotzdem von Interesse sein.
Vor noch nicht allzu langer Zeit, an einem nicht allzu weit entfernten Ort wurden einst alle Studis von einer schweren Programmiersprache dahingerafft ...
Aber nein! Nicht alle!
Eine kleine Gruppe unermüdlich lernender Studenten widersetzten sich dem Bösen, wild entschlossen diesem Missstand ein ende zu bereiten, setzten sie sich zusammen und schrien "FAQ-Opal" gen Himmel...
Nun ja, mehr spare ich mir hier, auf jeden Fall haben "damals" jede menge Leute in der Newsgroup informatik1 (bln.lv.tub.cs.informatik1) gepostet und sehr wertvolle Tips und Tricks zusammengetragen. Diese sind hier aufgeführt mit der ausdrücklichen Bitte, sie zu ergänzen.
Eine weitere (zum Großteil englische) Informationsquelle sind die offiziellen Dokumentationen. Außerdem gibt es seit 2012 Bestrebungen eine Web-Umgebung für OPAL zu entwickeln. Wer diese nutzen möchte, findet sie unter: http://opal.gehaxelt.in/, auch Entwickler sind herzlich willkommen: https://github.com/gehaxelt/PHP-Webopal/.
Inhaltsverzeichnis
- 1 Wie sieht eine OPAL-Struktur aus?
- 2 Wie sieht ein Kommentar in OPAL aus?
- 3 Wie konstruiert man eine Liste?
- 4 Benutzung des Interpreters oasys
- 5 Fehler/Probleme mit OPAL
- 5.1 Warum funktionieren Zahlen über 32 nicht?
- 5.2 Warum funktionieren (manchmal) auch Zahlen unter 32 nicht?
- 5.3 Warum funktionieren Kommazahlen nicht?
- 5.4 Warum kann man Denotations immer nutzen und Zahlen nicht?
- 5.5 Warum wird meine Backtick-Funktion (`) nicht benutzt?
- 5.6 Warum funktioniert WHERE nicht ohne weiteres mit Lambda-Ausdrücken?
- 5.7 Häufige Fehlermeldungen
- 5.8 Was ist Präfix-, Infix- und Postfixnotation?
- 5.9 Opal und Zugriffsrechte (ext2 versus fat)
- 5.10 Was bedeutet ein Fehler in Zeile 0?
- 5.11 Nicht nachvollziehbare Laufzeitfehler
- 5.12 oasys: Too many open files
- 6 Hilfreiche Tipps
- 7 Tabellen und Listen
Wie sieht eine OPAL-Struktur aus?
Minimalbeispiel für eine OPAL-Struktur
Na gut, es ginge noch kleiner, aber an diesem Beispiel kann man mehr erklären.
SIGNATURE MeineStruktur IMPORT Nat ONLY nat FUN meinPlus : nat ** nat -> nat
Für die Signatur (MeineStruktur.sign) und
IMPLEMENTATION MeineStruktur IMPORT Nat COMPLETELY FUN meinPlus : nat ** nat -> nat DEF meinPlus(a,b) == a + b
für die Implementierung (MeineStruktur.impl)
Zuallererst: Der Dateinname (ohne Endung), also der Name der Struktur, muss in der Schreibung exakt mit dem Namen der Signatur (hinter SIGNATURE
) und der Implementierung (hinter IMPLEMENTATION
) übereinstimmen und darf keine Leerzeichen oder Sonderzeichen enthalten. Nach Übereinkunft werden Strukturnamen mit großem Anfangsbuchstaben geschrieben.
Als nächster Begriff taucht in beiden Dateien IMPORT
auf. Hiermit werden andere Strukturen eingebunden. Diese müssen sich entweder im selben Verzeichnis befinden, oder zu OPAL gehören. Darauf folgt der Name der Struktur (im Beispiel Nat für die natürlichen Zahlen). In der Signatur folgt nun der Begriff ONLY
. Damit sagt man, dass man nur bestimmte Teile der Struktur benötigt, im Beispiel nat
(dies ist die Sorte der natürlichen Zahlen). Was man benötigt ist, in der Signatur, gewöhnlich nur das, was nach dem :
steht, ohne die Zeichen **
und ->
.
In der IMPLEMENTATION
sieht der Import etwas anders aus: hier wird COMPLETELY
benutzt. COMPLETELY
bedeutet, dass alles aus der Struktur in importiert wird, in diesem Fall also die Zahlen, Funktionen für Addition und Multiplikation und noch eine ganze Menge mehr (man könnte auch ONLY
benutzen, aber dann müsste man jede Funktion, Zahl, usw. hinter dem ONLY
notieren). Was nun folgt ist in beiden Dateien wieder das gleiche:
FUN meinPlus : nat ** nat -> nat
Hiermit wird eine Funktion deklariert, das Schlüsselwort FUN
bedeutet, dass an dieser Stelle eine Funktion angekündigt wird. Danach folgt der Name der Funktion (in diesem Fall meinPlus), nach dem Doppelpunkt folgt die Abbildung. Dies Funktion bildet zwei natürlichen Zahlen (nat
) auf eine natürliche Zahl ab. Einfacher: die Funktion nimmt zwei Eingabewerte an und gibt einen Wert zurück und alle Werte haben denselben Typ. D.h. es dürfen nur (in diesem Fall) nur Zahlen angegeben werden.
Hier endet die Signatur bereits, denn sie dient nur dazu anderen Strukturen zu zeigen was in der Struktur enthalten ist. Ähnlich einem Taschenrecher: aus der Taste seht ihr das Pluszeichen und wisst: dieser Taschenrechner kann addieren. Was ihr nicht wisst, ist wie intern addiert wird. Bei OPAL steht das in der Implementierung nach dem Begriff DEF
für Definition.
Wie sieht ein Funktions-Deklaration in OPAL aus?
FUN funktion : ausgabe
Für eine konstante Funktion. Diese Funktion wird aufgerufen und gibt immer den selben Wert zurück. In OPAL bspw. die Funktion pi, sie gibt immer (näherungsweise) Pi zurück.
FUN funktion : eingabe -> ausgabe
Für eine Funktion, die zu einem Wert übergeben bekommt und einen Wert zurück gibt. In OPAL bspw. die Funktion ~
sie erhält einen Wahrheitswert und negiert diesen.
FUN funktion : eingabe1 ** eingabe2 -> ausgabe
Für eine Funktion, die zwei Werte annimmt (ein Tupel) und daraus einen Wert macht. Beispiele in OPAL sind: +,-,*
.
FUN funktion : eingabe -> ausgabe1 ** ausgabe2
Für eine Funktion, die einen Wert erhält und ein Tupel zurück gibt. Eine solche Funktion könnte bei einem benannten Punkt als Eingabe, die Koordinaten als Tupel zurück geben.
Vor bzw. nach dem ->
können beliebig viele Eingaben bzw. Ausgabe notiert werden:
FUN funktion: eingabe1 ** eingabe2 ** eingabe3 -> ausgabe1 ** ausgabe2
Dies Funktion macht aus einem Tripel ein Tupel.
Wie sieht ein Kommentar in OPAL aus?
Warum überhaupt Kommentare?
Selbst geübte Programmierer wissen bei bestimmten Quelltexten nicht sofort, was sie bedeuten. Das einfachste Mittel um diesen Missstand auszuräumen ist die Nutzung von Kommentaren. Es gehört zum guten Stil seine Projekte angemessen zu kommentieren, außerdem sind Kommentare ein gute Gedächtnisstütze.
Wie sieht ein Kommentar in OPAL aus?
In OPAL gibt es zwei Arten von Kommentaren: einzeilige Kommentare und mehrzeilige:
-- Ich bin ein Kommentar.
Einzeilige Kommentare beginnen mit der Zeichenkombination --
, danach muss ein Leerzeichen folgen. Nach diesem Zeichen wird alles bis zum Ende der Zeile als Kommentar gewertet uns nicht weiter interpretiert.
/* Ich bin ein mehrzeiliger Kommentar /* P.S. Mich kann man verschachteln */ */
Ein mehrzeiliger Kommentar beginnt mit der Zeichenfolge /*
(hier muss nicht zwingend danach ein Leerzeichen gesetzt werden). Danach wird alles, was bis zur Zeichenfolge */
geschrieben wurde nicht weiter Interpretiert. Diese Kommentare eignen sich für längere Texte (z.B. Urhebervermerke, Lizenzen) und zum auskommentieren von unfertigem Code:
DEF test(<>) == <> /* Hier ist irgendwo ein Fehler DEF test(a::A) == IF a > 5 THEN a::<> ELSE test(A) <-- fehlt da was? */
Der vorige Quelltext ist fehlerhaft und würde deshalb nicht ausgeführt werden. Die fehlerhafte Stelle wurde auskommentiert, um das Programm ausführbar zu machen (außerdem wurde zusätzlicher Text vermerkt). D.h. ein Kommentar darf auch Schlüsselwörter enthalten, diese werden aber nicht beachtet.
DEF funktion(a,b) == IF a = b -- THEN c ELSE d FI
Die Funktion würde zu einem Fehler führen, denn das THEN
würde nicht mehr interpretiert werden, weil ein Kommentarzeichen davor steht.
Wie konstruiert man eine Liste?
Herzlichen dank für diesen Beitrag an Florian Lorenzen .
> Man kann dann viele aussagekräftige Beispiele mit :: und <> > angeben (seq, seq[seq], leere seq usw.)
Da ich, wie ich fürchte, mit diesem unsäglichen % angefangen habe -- nicht ahnend welchen didaktischen Flurschaden ich damit anrichten würde -- hier zum Ausgleich einige erklärende Beispiele mit den Listenkonstruktoren.
1. Sei S eine Sequenz aus alphas (FUN S : seq[alpha]).
DEF S == a :: b :: c :: d :: <>
S ist eine Sequenz aus a, b, c, d und der leeren Liste. Da :: rechtsassoziativ ist, wird der obige Ausdruck wie folgt aufgelöst:
~~~> a :: (b :: (c :: (d :: <>)))
Es wird also zunächst eine Liste aus d und <> konstruiert, vor die dann c gehängt wird. Die rekursive Struktur der Liste
Liste := Element :: Liste
ist deutlich.
DEF S == <>
S ist eine leere Liste.
Bei langen Elementen kann die Liste der Übersicht halber ohne weiteres auch umgebrochen werden.
"laaaaaaaaaaaaaaaaaaaaaaaaaaange Wortguppe" :: "nicht ganz so lange Wortgruppe" :: "etwas kürzere Wortgruppe" :: "noch kürzere Wortgr" :: "noch k" :: <>
vs.
"laaaaaaaaaaaaaaaaaaaaaaaaaaange Wortguppe" :: "nicht ganz so lange Wortgruppe" :: "etwas kuerzere Wortgruppe" :: "noch kuerzere Wortgr" :: "noch k" :: <>
2. Sei S eine Sequenz von Sequenzen von alphas (FUN S : seq[seq[alpha]]).
DEF S == (a :: b :: c :: <>) :: (d :: e :: <>) :: <>
Dieser Ausdruck wird wie folgt aufgelöst:
~~~> (a :: b :: c :: <>) :: ((d :: e :: <>) :: <>)
Es wird also zuerst eine Liste aus dem (d :: e :: <>) und <> kostruiert, vor die dann das Element (a :: b :: c :: <>) gehängt wird. Das die beiden erwähnten Elemente wiederum Listen sind, ändert nichts daran, wie die äußere Sequenz konstruiert wird.
DEF S == (a :: b :: c :: <>) :: <>
S ist eine Liste mit gerade genau einem Element, das wiederum eine Liste ist.
DEF S == <> :: <> :: <>
S ist eine Liste, die aus zwei leeren Listen besteht, nicht aus dreien, wie es zuerst scheint. Dies wird wiederum deutlich, wenn der Ausdruck aufgelöst wird:
~~~> <> :: (<> :: <>)
In der Klammer wird aus dem Listenelement "<>" durch ":: <>" eine Liste erzeugt, vor die dann das Element "<>" gehängt wird. dass die beiden Elemente der Liste nun leere Listen (dass es Listen seien müssen, ist sowieso klar) sind, ändert nichts daran, wie die äußere Liste konstruiert wird. Man beachte, dass die enstandene Liste nicht leer ist, dass also aus vielen leeren Listen eine nicht-leere Liste entstehen kann.
Eine Liste aus drei leeren Listen sieht dann dementsprechend folgendermaßen aus:
DEF S == <> :: <> :: <> :: <>
Eine Liste aus einer leeren Liste so:
DEF S == <> :: <>
Erst die Definition
DEF S == <>
erzeugt eine Liste von Listen, die wirklich leer ist.
Programmierpraktisch sollte beachtet werden, dass
S == <> :: <> oder S == <> :: <> :: <> :: ...
nicht durch <>?(S) oder das Muster f(<>) angefangen werden kann, da S eindeutig nicht leer ist.
Benutzung des Interpreters oasys
Starten von oasys, Ausführen von Programmen
Der OPAL-Interpreter oasys lässt sich von der Shell (auch Terminal oder Konsole) aus starten mit:
oasys
Um den Interpreter zu verlassen gibt man im Interpreter ein q für Quit ein:
> q
Hat man nun seine Dateien erstellt (z.B. Aufgabe1.impl und Aufgabe1.sign), muss man diese Dateien zuerst laden. Dafür muss man oasys in dem Verzeichnis starten, in dem die Dateien gespeichert sind. In welchem Verzeichnis ihr euch momentan befindet, erkennt ihr (meistens) an dem Verspann der Konsole.
user@opalix ~/MPGI1/HA1/ $
Dieser Nutzer befindet sich, ausgehend von seinem Benutzerverzeichnis, im Verzeichnis MPGI1/HA/. Welche Dateien und Ordner sich noch in diesem Verzeichnis befinden, kann man mit dem Befehl ls
oder dir
herrausfinden. Mir dem Befehl cd
kann das Verzeichnis gewechselt werden (in das übergeordnete Verzeichnis gelangt man bspw. mit der Angabe cd ..
:
user@opalix ~/MPGI1/HA1/ $ cd .. user@opalix ~/MPGI1/ $
Also wechselt in das Verzeichnis wo sich die Dateien Aufgabe1.impl und Aufgabe1.sign beispielsweise befinden und starten von dort aus auf der shell den OPAL-Interpreter oasys. Wenn ihr oasys gestartet habt, könnt ihr das Verzeichnis nur wechseln, wenn ihr oasys vorher beendet (mit dem Befehl q
), es ist jedoch ohne Probleme möglich eine weitere Shell zu öffnet und dort oasys in einem anderen Verzeichnis zu starten.
Als nächstes müssen die Dateien dem Interpreter zur Verfügung gestellt werden. Mit dem Interpreter-Befehl a (append file = Datei anfügen) lassen sich Dateien in den Interpreter laden. Dabei gibt man nur den Dateinamen ohne die Dateiendung an (bei langen Namen kann die Tab
-Taste zur automatischen Vervollständigung genutzt werden, der Punkt am Ende ist egal).
> a Aufgabe1 loading Aufgabe1.impl loading Aufgabe1.sign >
Wenn die Dateien erfolgreich geladen wurden wird das wie hier in dem Beispiel gezeigt quittiert. Außerdem erstellt oasys ein Verzeichis namens OCS.
Für oasys ist es notwendig, dass man zunächst den Fokus auf eine spezielle Datei legt. Dies erreicht man mit dem Befehl f (f für set focus). Wenn man die impl-Datei fokussiert, kann man auf alle Funktionen zugreifen die in dort implementiert wurden. So kann man aber unter Umständen vergessen eine vernüftige Signature (sign-Datei) zu schreiben und eine entsprechende Kapselung vorzunehmen (wichtig sobald mit mehr als einem Modul gearbeitet wird). Es ist gut sinnvolle Kapselung gleich mit zu lernen.
> f Aufgabe1.impl Aufgabe1.impl>
oder: um zu testen welche Funktionen von außen erreichbar sind:
> f Aufgabe1.sign Aufgabe1.sign>
Wenn das Fokussieren funktioniert hat, verändert sich eure Eingabe wie im Beispiel angegeben. Um Funktionen auszuführen befehligt man oasys mit dem Befehl e (e für evaluate). Dabei wird aus der fokussierten Datei eine Funktion mit den Parametern die ihr in der Signatur festgelegt habt ausgewertet. Um diese vielen Begriffe zu verdeutlichen gehen wir mal davon aus, dass wir in der Datei eine Funktion add implementiert haben die zwei ganze Zahlen addiert. Diese Funktion ruft man dann so auf:
Aufgabe1.impl>e add(1,2) starting evaluator process 3 Aufgabe1.impl>
Eingabe von Zahlen, Denotations (Strings), Sequenzen und einzelne Buchstaben (Chars)
Beispiel:
> e funktionMitVielenArgumenten("lkajbblsd", "627849"!, 30,"c"!, %(1,23,9,1,8))
Erklärung: Das erste Argument ist eine Denotation, d.h. einfach ein String. Die muss man einfach immer in Anführungszeichen setzen. :)
Das zweite ist eine Zahl. Da sie größer als 32 ist muss man sie als String hinschreiben (Anführungszeichen), den man dann mit dem Operator "!" in eine Zahl umwandeln kann.
Das dritte ist eine kleinere Zahl als 32, daher kann man sie direkt hinschreiben.
Das vierte ist ein Char, also ein einfacher Buchstabe. Da man das nicht direkt eingeben kann übergibt man Opal wieder einen String und wandelt ihn (da er nur einen Buchstaben enthält) mit dem "!" in einen Char um.
Das fünfte ist eine Sequenz, man kann sie direkt in dieser Form hinschreiben, zu beachten gibt es nur ;) dass man so höchstens 8 Elemente verknüpfen kann. Will man mehr eingeben muss man eben 2 (oder noch mehr) dieser Dinger mit ++ verknüpft hinschreiben.
Diese Art Sequenzen zu schreiben eignet sich für Programmtests, wenn man sich die etwas umständliche Schreibweise sparen möchte. Wenn in einer Aufgabe der Umgang mit Listen geprüft werden soll, wird diese Schreibweise nicht empfohlen, da sie den rekursiven Aufbau der Liste verschleiert. Wenn eine Liste aber ähnlich einer Menge benutzt wird, ist die %
-Schreibweise durchaus legitim.
Bsp: eine seq[nat] könnte man also so schreiben.
%(4,3,5,8,2,21,5,5) ++ %(6,"78"!,"269"!,"987"!,"654"!,"321"!)
Eine seq[seq[nat]] könnte man dann so schreiben
%( %(1,3,2), %(1,2,3))
(man beachte die notwendige Umwandlung da die Zahlen zum Teil größer als 32 sind. :))
(!!!) Vorsicht (!!!) man sollte im Normalfall keine Leerzeichen zwischen die Argumente setzen! Das funktioniert zwar meistens, leider aber nicht immer! (Das gilt natürlich nur für die Kommandozeile, in den Syntax-Files selber sind Leerzeichen ziemlich wurscht. :))
Also nochmal: Vorsicht vor Leerzeichen in Funktionsaufrufen!
Ich hatte schon Fehlermeldungen weil ich in Funktionen nach dem Komma ein Leerzeichen eingebaut hatte.
Bsp: func1("9023"!, "0234"!)
Lässt man das weg, funktionierte (bisher) alles:
func1("9023"!,"0234"!)
Speziell wenn man Texte in Nummern umwandelt (siehe oben) scheint das zu Problemen zu führen. (Dieses Problem hatte ich selbst bisher nur wenn ich von der Shell (Kommandozeile aus direkt Argumente in eine Funktion füttern wollte. Ansonsten trat es nicht auf. :)
Oasys an der Shell herumkommandieren:
Herzlichen Dank an Roman Lechtchinsky
Warum funktioniert der Aufruf
> e f(\\x. 2 * x, 4)
unter oasys nicht?
Das liegt daran, dass Du in oasys fuer jeden Backslash \\ eingeben muss, also
> e f(\\\\x. ...)
Das hat nichts mit OPAL zu tun, sondern mit der Skript-Sprache (TCL), in der das Interpreter-Frontend implementiert ist (nehme ich zumindest an). Anm.: angeblich ist die readline-Bibliothek verantwortlich...
Alternativ kann man das quote von TCL (das sind geschweifte Klammern) um den ganzen Ausdruck legen, dann kann man es auch bequem, wie in einer Datei eingeben, also
> e {f(\\x. 2 * x, 4)}
Fehler/Probleme mit OPAL
Warum funktionieren Zahlen über 32 nicht?
In Opal sind die Zahlen auch Funktionen (genauer konstante Funktionen), d.h. wenn eine Zahl eingeben wird, wird eine Funktion mit dem Namen der Zahl ausgeführt, die die Zahl als Wert zurückgibt. Deshalb müsste für jede Zahl eine Funktion existieren. Da das nicht möglich ist, gibt es eine Funktion, die eine Zeichenkette (denotation) in eine Zahl umwandelt. Diese Funktion heißt !
:
"zahl"!
Aber warum funktioniert das bei Zahlen unter 32 auch ohne diese Funktion? Naja, einige Zahlen sind für bequemeres Eingeben doch als Funktion definiert:
Die Zahlen von 0
-32
, die Zweierpotenzen 64,128,256,512,1024
und die Zahlen 100, 1000, 10000, 100000, 1000000
. Daneben gibt es noch die Konstanten pi
und e
für die ludolfsche Zahl (Pi) und die eulersche Zahl.
Warum funktionieren (manchmal) auch Zahlen unter 32 nicht?
Dies ist meistens der Fall, wenn das Programm mit oasys über die Signatur aufgerufen wird. In der Signatur werden meistens nur die Sorten (bspw. nat
, denotation
) importiert, da Zahlen auch Funktionen sind, müsste man diese auch importieren. Etwas flexibler ist es, die Umwandlungsfunktion !
zu importieren. Dann müssen zwar alle Zahlen erst von einer Zeichenkette umgewandelt werden, aber so kann man überhaupt mit Zahlen arbeiten:
IMPORT Nat ONLY nat !
Natürlich kann man auch COMPLETELY
statt ONLY
benutzen. Dies wird aber teilweise als schlechter Stil empfunden.
Warum funktionieren Kommazahlen nicht?
Zuallererst: Kommazahlen werden in Opal mit einem Punkt notiert, bspw. ist 3,14159
in Opal 3.14159
.
Wie bei der Frage zu Zahlen über 32 bereits beschrieben, müssten gleich benutzbare Zahlen als (konstante) Funktion in einer Struktur definiert (und deklariert) sein. Das ist nicht der Fall (außer bei pi
und e
). Der Standardfehler den oasys
in diesem Fall ausgibt ist:
ERROR [at ...] no matching operation for . ERROR [check] language error
oasys
hält also das Komma (den Punkt) für eine (binäre) Funktion. Um Kommazahlen in Opal zu benutzen, müssen sie "kontruiert" werden. Hierfür enthalten Strukturen, die Kommazahlen nutzen, die Funktion !
. Kommazahlen werden also als Denotation geschrieben: "3,14159
" und dann mit der (unären) Funktion !
umgewandelt: !"3,14159
" oder "3,14159
"!, inbesondere bei der Nutzung in längeren Gleichungen oder der oasys-Eingabe kann dieses Ausrufezeichen (da unär) schon einmal für unerwartete Fehler sorgen (mehr dazu Was ist Präfix-, Infix- und Postfix-Notation?).
Warum kann man Denotations immer nutzen und Zahlen nicht?
Wenn eine OPAL-Struktur interpretiert (und später übersetzt) wird, lädt der Interpreter bestimmte Strukturen automatisch. Diese heißen bspw. BOOL
und DENOTATION
und stellen elementare Funktionen zur Verfügung. Deshalb kann man ohne den Import von irgendwelchen Strukturen IF-THEN-ELSE-Konstrukte in OPAL nutzen und mit Denotations arbeiten (nicht aber mit Zahlen, denn die werden nicht automatisch importiert). Die in der Schreibung ähnlichen Strukturen Bool
und Denotation
stellen aber noch weitere Funktionen zur Verfügung, deshalb müssen sie gelegentlich doch importiert werden.
Warum wird meine Backtick-Funktion (`) nicht benutzt?
Die Backtick-Funktion für eigene Datentypen muss in der .sign-Datei mit deklariert sein.
Warum funktioniert WHERE nicht ohne weiteres mit Lambda-Ausdrücken?
Wenn man Lambda mit WHERE kombinieren will muss man den ganzen Body der Funktion klammern
Das geht so:
DEF qsolve1 == \\ a, b, c .( /* <--- */ (x1, x2) WHERE x1 == (-(b) + d) / (2 * a) x2 == (-(b) - d) / (2 * a) d == sqrt((b * b) - (4 * a * c)) ) /* <----- */
Wichtig ist dabei, dass nach dem Punkt, mit dem der Lambda Ausdruck die Argumentliste abschließt, kein Leerzeichen oder irgendetwas anderes ist, sondern gleich die öffnende Klammer kommt. Ansonsten funktioniert es nicht!
Häufige Fehlermeldungen
Folgende Fehlermeldung ist ziemlich haeufig:
Expected ... instead of ....
Hier handelt es sich um einen einfachen Syntaxfehler. Falls Ihr meint, alles korrekt geschrieben zu haben, überprueft auch nochmal die Klammerung der Ausdrücke (es muss genausoviele öffnende wie schliessende Klammern geben). Vielleicht ist ja auch nur ein FI vergessen worden...
Expected was `:' instead of `->'
Dieser Fehler kann trotz korrekt vorhandenem :
auftreten. Beispiel:
FUN `: nat -> stream -> denotation
erzeugt den Fehler, dahingegen
FUN ` : nat -> stream -> denotation
nicht.
Es hilft also eventuell das Einfügen von Whitespace.
improperly named function definition target or parameter ...
In diesem Fall sollte man ueberpruefen, ob die Deklaration der Funktion (FUN ...) fehlt. Vielleicht ist gerade dieser Teil auskommentiert, oder man hat schlicht und einfach vergessen, die Signaturdatei zu speichern. Mir ist letzteres auch schon unterlaufen, d.h. man sucht nach einem Fehler, der eigentlich nicht vorhanden ist.
missing else in ...
Passiert, wenn bei der Verwendung des Dijkstra-IFs während der Auswertung ein Fall eingetreten ist, der nicht abgedeckt wird. Bei dieser Funktion würde es z.B. bei testeZahl(10) auftreten:
DEF testeZahl(x) == IF x > 10 THEN true IF x < 10 THEN false FI
Es müsste ein < oder > durch <= bzw. >= ersetzt werden, oder der Fall = explizit aufgeführt werden.
ambigious infix application
Dieser Fehler deutet darauf hin, dass bei Infix-Notation die Klammern nicht eindeutig gesetzt werden konnten. Ein Beispiel sind die logischen Funktionen /\
(und) und \/
(oder). Opal hat hierfür keine Klammerregelung, der Ausdruck
false /\ true \/ true
kann auf zwei Arten geklammert werden: entweder (false /\ true) \/ true
(ausgewertet zu true) oder false /\ (true \/ true)
(ausgewertet zu false).
Was ist Präfix-, Infix- und Postfixnotation?
...oder wie man Minuszeichen hassen lernt.
Bei der Präfix-Notation wird der Funktionsname vor den Argumenten geschrieben, bspw. !"33"
, oder +(3,5). Bei Funktionen mit mehr als einem Parameter müssen die Argumente in Klammern gesetzt und durch Kommas getrennt werden.
Die Infix-Notation ist nur bei zweistelligen (oder binären) Funktionen möglich (also Funktionen mit genau zwei Parametern). Beispiele dafür sind die Funktionen +, /\, *,
usw.:
5 + 6 true /\ false 4 * 6
Bei den meisten zweistelligen Funktione sind auch solche Konstruktionen möglich: 3 + 4 + 9 + 2
, die Klammerung wird implizit vorgenommen, auch Mischungen wie 3 + 4 * 7 + 3
werden den mathematischen Gesetzen entsprechend geklammert.
Die Postfix-Notation ähnelt der Präfix-Notation, nur dass hier hier der Funktionsname nach den Parametern notiert wird. Bspw. "33"!
oder (6,3)-
.
Insbesondere bei einstelligen (unären) Funktionen, wie !
, oder -
(als Vorzeichen), kommt es öfter zu solchen Fehlermeldungen:
ERROR [HOF.impl at 32.5-32.33]: undefined identification 1. <32,5-33> wrongly typed implementation left: real->real right: ((nat**nat->nat)->real)->real 2. <32,5-33> wrongly typed implementation left: real->real right: ((real**real->real)->real)->real 3. <32,5-33> wrongly typed implementation left: real->real right: ((real->real)->real)->real ERROR [check]: language error aborted
Könnte das etwas mit dem Gebrauch von Minuszeichen zu tun haben. :(
Ich hatte größte Schwierigkeiten den folgenden Code zum Funktionieren zu überreden, Code-Zeilen wie das hier:
FUN test : ( real -> real ) -> ( real -> real ) DEF test( r ) == \\ x . r( -x )
Funktionieren nicht.
Das Problem ist das der Compiler für das minuszeichen ( r( -x )) zwei Argumente zu erwarten scheint. (Obwohl er das laut Spezifikation nicht müsste)
Die Löung lag für mich darin entweder "0 - x" zu schreiben oder das x in eigene Klammern zu setzen ( x ). Beides funktioniert hier.
Einen änlichen Fehler hatte ich als ich so etwas schreib: " a - b + c "
Ich musste das dann als ( a - ( b + c ) ) schreiben damit es funktionierte.
Hope it helps!
Hier habe ich noch eine Erklärung von Klaus Didrich bekommen (thx!)
Das Prinzip, dass Funktionen keine Sonderbehandlung erfahren, erstreckt sich auch auf das unäre Minuszeichen. Folgendes geht:
-(1) (analog zu "f(1)") (1-) (analog etwa zu "(5!)")
Dein Problem mit "a - b + c" kann ich allerdings nicht nachvollziehen.
Und gleich nochmal etwas, hierfür danke ich Archi Varius.
+ ( 0, 1 ) = 0 + 1 = ( 0, 1 ) + ! 5 = 120 = 5 ! - 1 = 1 -
Und nochmal. :)) Diesmal herzlichen Dank wieder an Klaus Didrich.
Wird den in Opal, jeder Infixoperator der nur einen Operand bekommt hinter den Operand geschrieben wird? (Das fände ich ja etwas beschränkt...)
- Es ist viel schlimmer :-) Es ist beides möglich. Du kannst jeden einstelligen Operator auch hinter den Operanden schreiben, dazu brauchst Du keine besondere Deklaration.
- Ob man IF <>?(S) THEN ... oder IF S <>? THEN ... schreibt, macht keinen Unterschied. Eine Mischung aus Postfix- und Infix-Applikationen kann der Compiler leider nicht analysieren, da kommt dann die Meldung "no possible bracketing for infix found". In dem Fall hilft Klammern: (5!) + 3, (S#) > 0
- Auch bei zweistelligen Funktionen kann man es sich aussuchen, ob man die Präfix- oder die Infixschreibweise vorzieht: +(5,3) oder 3 + 5 sind beide erlaubt.
Opal und Zugriffsrechte (ext2 versus fat)
Herzlichen Dank für diesen Tip an Thomas Brinker!
Du setzt Opal unter Linux ein
Opal-fehlermeldung: Operation not permitted
Grund: Die Dateien liegen nicht in einer ext2-Partition sondern in einer FAT-Partition. (in FAT geht das mit den named Pipes nicht)
Abhilfe:
Dateien in ext2 Partition umkopieren. Alternativ die aktuelle Opal-Version 2.3m benutzen, wenn /tmp auf einer Partition liegt, die named Pipes unterstützt.
Im Grunde das gleiche wie vorher, siehe Opalix-Seite.
Was bedeutet ein Fehler in Zeile 0?
Bei einem ansonsten korrekten Programm hat mich diese Fehlermeldung vorhin eine laaange Fehlerjagd gekostet...
Person.impl>e Birthday(date(30,12,"79"!) ERROR [at 0.3-0.4]: Expected was `)' instead of `IN' ERROR [check]: language error aborted
In diesem Fall hatte ich auf der Eingebe-Zeile im Interpreter eine schließende Klammer vergessen. :))
Man kann diese Fehler recht leicht erkennen. Sie finden immer auf Zeile 0 statt. Das ist die Eingabe-Zeile in der Shell. :)) (" ERROR [at 0.3-0.4]:")
Der Fehler muss folglich auch nicht immer ein Syntax-Fehler sein (wie oben), sondern kann auch durch die Sprache in der die Eingabe von oasys
programmiert ist hervorgerufen werden (siehe Oasys an der Shell herumkommandieren).
Nicht nachvollziehbare Laufzeitfehler
Wenn das eigene Programm eine Struktur S enthält und die Bibliotheca Opalica ebenfalls eine Struktur S bereitstellt, kann es unter Umständen zu nicht nachvollziehbaren Laufzeitfehlern komen, wie etwa
RUNTIME ERROR: TreeConv at <252,5-11> : missing else in asSeqIn'TreeConv:tree**seq->seq Aborted (core dumped)
unter Ubuntu oder
Bus Error (core dumped)
unter Solaris 10 Sparc.
In diesem Fall enthält das Programm eine Struktur Tree und die Bibliotheca Opalica hat ebenfalls eine solche Struktur.
Die einzige Lösung des Problems ist die Umbenennung der Struktur S, da alle zu einem Opal-Programm gelinkten Strukutren verschiedene Namen haben müssen. Eine Übersicht aller in der Bibliotheca Opalica vorhandenen Strukturen gibt es bspw. über den "Structure Index" der Dokumentation: http://projects.uebb.tu-berlin.de/opal/dosfop/latest/bibopalicaman/Structure_Index.html, Alternativ können die Befehle l
, oder ll
(umfangreicher als l
) in oasys benutzt werden.
Es ist ein Bug im Opal-Compiler, dass in solchen Fällen keine Fehlermeldung ausgegeben wird, sondern es so aussieht als ob das Programm korrekt übersetzt wurde. Details können in diesem Ticket nachgelesen werden: http://projects.uebb.tu-berlin.de/opal/trac/ticket/50
Unter MacOS X tritt das Problem aufgrund des Mach-O Formats und einer anderen Link-Semantik nicht auf.
oasys: Too many open files
oasys detektiert einen verboteten zyklischen Import innerhalb von IMPLEMENTATIONs nicht.
Es gibt stattdessen die Fehlermeldung sobald eine Funktion des Programms ausgewertet wird:
starting evaluator process sh: 1: 1: Too many open files evaluator: cannot retrieve symbols of `pconn-in-289-25/10/94' connection lost
Ausserdem werden im temporären Verzeichnis (z. B. /tmp) Unmengen von Dateien liegengelassen.
Zyklische Importe sind in Opal verboten. Die einzige Losung ist also eine Umstrukturierung des Programms. Der Opal-Compiler ocs detektiert das Problem korrekt.
Hilfreiche Tipps
Zwischenergebnisse zur Fehlersuche ausgeben (printf
-Debugging)
Oftmals wünscht man sich eine Möglichkeit, Zwischenergebnisse auf der Konsole auszugeben, z.B. um Fehler zu finden und den Programmablauf zu verfolgen. Da man in einer rein-funktionalen Sprache wie Opal nicht einfach ein printf
einfügen kann, muss man etwas tricksen. Mit Hilfe der "Funktion" EXEC
aus der Com
-Struktur kann aus dem Ablauf heraus Text ausgeben, da sie eine Möglichkeit darstellt, Seiteneffekte auszufühen. Das sieht dann so aus:
SIGNATURE DebugHelper[ResultType] SORT ResultType FUN || : ResultType ** denotation -> ResultType
IMPLEMENTATION DebugHelper[ResultType] IMPORT Com COMPLETELY Stream COMPLETELY ComCompose COMPLETELY FUN || : ResultType ** denotation -> ResultType DEF result || msg == EXEC(writeLine(stdOut, msg); succeed(result))
Speichert die beiden Code-Schnippsel in den Dateien DebugHelper.{sign,impl}
und schon könnt ihr auf einfachste Weise Debug ausgaben machen. Schreibt dafür einfach die Debugausgabe auf die rechte Seite des "Debugoperators" ||
.
Beispiel:
IMPLEMENTATION Beispiel IMPORT Nat COMPLETELY NatConv COMPLETELY Denotation COMPLETELY DebugHelper COMPLETELY FUN foo: nat ** nat -> nat DEF foo(x, y) == LET res == (x + y) || "in x=" ++ `(x) ++ " y=" ++ `(y) IN res || "out =" ++ `(res)
Output:
Beispiel.impl>e foo(2,3) starting evaluator process in x=2 y=3 <<----- Debug out =5 <<----- Infos 5 Beispiel.impl>
Ähnliche Funktionalität bietet auch die DEBUG
Struktur aus der Bibliotheca Opalica, allerdings sind dort die Funktionen IMHO nicht ganz so schön einzubauen.
Syntax Highlighting
Anleitungen und Vorgaben zum Opal Syntax-Highlighting finden sich auf einer extra Seite.
Opal-Quelltexte mit TeX/LaTeX setzen
TeX/LaTeX ist ein sehr mächtiges Textsatzsystem, das für kleinere Dokumente über Diplomarbeiten bis hin zu kompletten Büchern verwendet werden kann.
Da liegt es nahe, einfach auch Hausaufgaben optisch ansprechend in hoher Qualität damit setzen zu lassen.
Für das Setzen von Quellcodes gibt es u.a. das Listings-Package für TeX/LaTeX. Hier gibt es jedoch kein vordefiniertes Syntax-Highlighting für OPAL. Außerdem steht die opal2x.sty [1], [2] zur Verfügung.
Opal für Windows
Kurz: Es gibt kein Opal für Windows.
Lang: Jedenfalls in keiner benutzbaren Fassung. Im Rahmen einer Dissertation entsteht zwar Opal.NET (also Opal für die MS .NET Plattform), diese Version wird jedoch vorraussichtlich nicht als "stable release" erscheinen.
Opal unter Cygwin
Opal unter Cygwin wird nicht von der PSS Gruppe unterstützt und funktioniert erfahrungsgemäß nicht.
Erfahrungsbericht von Tobias Deichmann in der Info1 Newsgroup:
- ...also ich hab mich da letztes Jahr knapp 4 Wochen lang dran probiert und kann dir nur einen Tipp geben: Lass es.
- Hab es zwar soweit geschafft, dass wenigstens einige Kommandozeilenbasierende OPAL-Programme wenigstens halbwegs fehlerfrei liefen (ok, sie stürzten trotzdem einigermaßen oft ab oder wir man das auch immer bezeichnen möchte), aber das richtige Problem kommt erst, wenn du das Ganze dann noch mit der grafischen Java Benutzeroperfläche (kurz GUI) von OPAL verwenden willst. Da funktioniert dann gar keins der Programme, es zerschießt dir dabei regelmäig die komplette cygwin bzw. OPAL Installation und es ist einfach nervig. Mein Rat an dich ist also, es lieber mit Opalix oder sonstwas zu probieren, als dich durch cygwin zu quälen, denn das führt eigentlich zu nichts...
Als Alternative bieten sich Opalix und Opal für Linux an.
Opal via SSH
Eine weitere Möglichkeit Opal von Zuhause aus zu benutzen ist sich über SSH auf einen der Uni-Server zu verbinden und so "remote" zu arbeiten. Welche Server zur Verfügung stehen und wie SSH benutzt wird steht auf der SSH-Seite.
Tabellen und Listen
Anmerkung: Die folgenden Tabellen werden noch erweitert.
Wichtige Strukturen
Name | Inhalt | Auswahl von Funktionen |
---|---|---|
Nat | Stellt Funktionen und Sorten der natürlichen Zahlen bereit | +,-,*,div,mod |
NatConv | Stellt Funktionen zur Umwandlung von natürlichen Zahlen in andere Typen bereit | asChar, asInt, asReal, ` |
Real | Stellt Funktionen und Sorten der reellen Zahlen bereit | +,-,*,/ |
RealConv | Stellt Funktionen zur Umwandlung von reellen Zahlen in andere Typen bereit | asNat, asInt, `, `` |
Int | Stellt Funktionen und Sorten der ganzen Zahlen bereit | +,-,*,div,mod |
IntConv | Stellt Funktionen zur Umwandlung von reellen Zahlen in andere Typen bereit | asNat, asReal, ` |
Bool | Stellt Funtionen und Sorten für boolsche Ausdrücke zur Verfügung | /\, \/, => |
BoolConv | Stellt eine Funktion zur Umwandlung von Wahrheitswerten (true/false) in Text zu Verfügung | nur ` |
Char | Stellt Funktionen für Buchstaben und Zeichen/Eingaben zur Verfügung | pred, newline, lower?, whitespace? |
CharConv | Stellt Funktionen zur Umwandlung von Buchstaben/Zeichen zur Verfügung | `, asNat, asDigitNat |
Denotation | Stellt Funktionen für Textverarbeitung zur Verfügung | #, slice, empty? |
String | Stellt Funktion für dynamische Textverarbeitung bereit | #, empty?, ++, % |
StringConv | Stellt Funktionen zur Umwandlung von Zeichenketten bereit | asSeq, asString, ` |
Seq | Stellt Grundfunktionen für die Arbeit mit Listen zur Verfügung | <>, ::, exist?, % |
SeqConv | Stellt eine Grundfunktion zur Umwandlung von Listen bereit | nur ` |
SeqFilter | Stellt eine Filterfunktion auf Listen zzgl. Hilfsfunktionen zur Verfügung | filter, partition, split |
SeqMap | Enthält eine Funktion zur Umwandlung von Listen | nur map oder * |
SeqReduce | Stellt Funktionen zur Reduktion von Listen bereit | reduce oder /, \ |
SeqZip | Stellt Funktionen zum Zusammenfügen und Zertrennen von Listen zur Verfügung | zip, unzip |
Option | Stellt einen Zugriffstyp und Zugriffsfunktionen für Datentypen zur Verfügung | cont, <, = |
Compose | Stellt Funktionen zur Komposition von Funktionen bereit | o, ; |
Tree | Stellt Grundfunktionen zur Arbeit mit Bäumen zur Verfügung | lrotate, %, # |
TreeConv | Stellt Funktionen zur visuell ansprechenden Ausgabe von Bäumen bereit | asSeqIn, `, graphic |
Com | Stellt Grundfunktionen für die Behandlung von Monaden bereit | succeed, yield, break |
ComCompose | Funktionen zur Komposition von Monaden | &, ; |
BasicIO | Stellt Grundfunktionen für Ein- und Ausgabe bereit | ask, writeLine, write |
File | Stellt Funktionen für den Dateizugriff zu Verfügung | open, reopen, close |
Void | Stellt einen leeren Datentyp bereit (wichtig für Monaden) | nur void (Datentyp) |
Außerdem stellt OPAL die Struktur Basics zur Verfügung, diese lädt automatisch folgende Strukturen: ABORT, BOOL, Bool, BoolConv, Char, CharConv, DENOTATION, Denotation, Int, IntConv, Nat, NatConv, Real, RealConv.
Hinweis: Einige Strukturen importieren bereits andere, die Einzelheiten finden sich in der Referenz.
Interessante Strukturen
Anmerkung: Diese Strukturen werden im Studium nicht zwingend behandelt, enthalten aber interessante Zusatzinformationen und erleichtern die Arbeit, wenn man über die Studieninhalte hinaus mit OPAL experimentieren möchte. Einige Strukturen sind auch hilfreich bei der sinnvollen Strukturierung von eigenen Strukturen (auch bei Hausaufgaben).
Name | Inhalt | Auswahl von Funktionen |
---|---|---|
ABORT | Lässt eigene Fehlerbehandlungstexte zu | nur ABORT |
Set | Struktur die Funktionen und Typen auf Mengen enthält | {}, incl, forall? |
Wichtige Funktionen
Anmerkung: Funktionen mit demselben Namen verhalten sich in verschiedenen Strukturen ähnlich (Prinzip der Orthogonalität). Einige Funktionen heißen aber auch gleich und machen völlig verschiedene Dinge. Für viele Funktionen gibt es mehrere Namen.
Name | weitere Namen | Beschreibung | enthalten in |
---|---|---|---|
div | / | Divisions-Operator (für ganze Zahlen) | Nat, Int |
mod | % | Rest der ganzzahligen Division | Nat, Int |
/ | keine | Divisionsoperator | Real |
pow | ^ | Potenzfunktion | Nat, Int, Real |
++ | keine | Konkatenation von Werten | Denotation, String, Seq |
even? | keine | Gibt an, ob eine Zahle gerade ist | Nat, Int |
odd? | keine | Gibt an, ob eine Zahl ungerade ist | Nat, Int |
Wichtige oasys-Befehle
Mehr zu dieser Tabelle: http://projects.uebb.tu-berlin.de/opal/trac/raw-attachment/wiki/Documentation/OasysManual.pdf
Befehl | LF | Bedeutung | Beispiel |
---|---|---|---|
a | append | Füge eine Struktur hinzu | a MeineStruktur
|
f | focus | Öffne einen Teil der Struktur (Signatur oder Implementierung) | f MeineStruktur.impl
|
e | evaluate | Werte einen Ausdruck aus | e meineFunktion(12,"33"!)
|
ex | evaluate execute |
Werte einen Ausdruck aus, führe die resultierenden Kommandos aus | ex meineMonadenFunktion
|
x | execute | Führe das Kommando (die Funktion) aus | x meineMonadenFunktion
|
r | reload | Erzwingt das Neuladen von veränderten Strukturen | r ohne Argument
|
l, ll | list | Liste alle bekannten Strukturen auf (l: Kurzversion, ll: Langversion) | l , oder ll ohne Argument
|