-Einleitung:
Allgemeine Information über PD-Scheme

PD-Scheme ist lediglich eine  experimentelle  Programmiersprache.  Es  wurde
NICHT für professionelle  Anwendungen  geschaffen, sondern ist nur eine "ra-
pid prototype" Version eines zukünftigen Scheme-Projektes. Weiterhin sei er-
wähnt, da₧ PD-Scheme keineswegs frei von Konflikten,  bezüglich des  Scheme-
Standards ist,  wenn auch so ziemlich alle Standard-Scheme-Funktionen imple-
mentiert sind. 
Als  Entwicklungssprache zu PD-Scheme diente GFA-Basic V3.0.  Leider  kompi-
liert der aktuelle GFA-Basic-Compiler 3.02 PD-Scheme nicht vernünftig, soda₧
es eigentlich nur mittels des Interpreters einsatzfähig ist.  Das ist insbe-
sondere deshalb schade,  weil die kompilierte Version von PD-Scheme doch  um
einiges schneller ist.  Deshalb bleibt zu hoffen, da₧ bald eine Compilerver-
sion erscheint die in der Lage ist, PD-Scheme fehlerfrei zu übersetzen.
Nichtsdestotrotz ist PD-Scheme auch in der Interpreterversion eine  durchaus
interessante Programmiersprache. Au₧erdem hat dies für alle  Besitzer  eines
GFA-Basic Interpreters den Vorteil,  da₧ sie den Quelltext zur Verfügung ha-
ben.  Dies ermöglicht es Ihnen,  eigene Modifikationen am Quelltext durchzu-
führen, um somit PD-Scheme an eigene Vorstellungen anzupassen.

Hiermit erteile ich jedem die Erlaubnis,  PD-Scheme nach eigenem ermessen zu
verändern oder zu erweitern,  sowie veränderte und/oder erweiterte Versionen
in Umlauf zu bringen.

Frank Hinkel    ( Auf eine handschriftliche Unterschrift mu₧te leider ...)

~
-Primitives:
Primitive Operationen in PD-Scheme

Um eigene primitive Operationen einzuführen,  sind folgende Schritte notwen-
dig:
       1. In der Prozedur "setup_primitives" ist der Name der neuen Funktion
          in einer "DATA"-Zeile einzutragen.  Dabei belegt eine Funktion je-
          weils 4 Einträge, die wie folgt vorzunehmen sind:
        
            DATA <name>,<min-parrameter>,<max-parameter>,<textstyle>

            <name>          : Der Name der neuen Funktion.
            <min-parameter> : Die minimale Anzahl von Parametern.
            <max-parameter> : Die maximale Anzahl von Parametern.
                              Wobei "-1" für beliebig viele Parameter steht.
            <textstyle>     : Gibt den Textstil für die Anzeige auf dem
                              Bildschirm an. ( siehe GFA-Basic DEFTEXT )
                              Zur Zeit au₧er Funktion.
~
          Dazu ein Beispiel:

            DATA LIST,0,-1,8

          bedeutet,  da₧ die Funktion LIST Null bis beliebig viele Parameter
          erwartet.  Die "8" bedeutet,  da₧ LIST, wenn es auf dem Bildschirm
          angezeigt wird, unterstrichen wird.

       2. In den entsprechenden "apply" Funktionen wird  der  Funktionnsname
          in die "CASE"-Liste aufgenommen und der entsprechende Programmcode
          zur Implementierung der gewünschten Funktion hinzugefügt.  An die-
          ser Stelle haben Sie folgende Vorgaben:

                a) l% zeigt auf die Liste der Aufrufparameter. Mit LPEEK(l%)
                   oder eleganter {l%} greifen Sie auf  den  "CAR"-Teil  der
                   Liste zu und mit LPEEK(l%+4) b.z.w. {l%+4} auf den "CDR"-
                   Teil. Beachten Sie bitte, da₧ bei  primitiven  Funktionen
                   die Parameterliste noch nicht evaluiert ist.  Sie  müssen
                   explizit mit der Funktion "eval" evaluiert werden.

                b) Die Variable env% enthält das aktuelle Environment.

~
                c) Der Variablen r% müssen Sie, nach Abarbeiten Ihrer  Funk-
                   tion, den Funktionswert zuordnen.

       Um eigene primitive Funktionen zu implementieren, sollten sie die Im-
       plementierung der bereits vorhandenen Funktionen studieren, um daraus
       die nötigen Informationen zu extrahieren.

Aber auch wenn Sie nicht vorhaben, eigene primitive Funktionen zu schreiben,
können Sie mit Hilfe der Prozedur  internal_init eigene Funktionen in Scheme
schreiben,  die vor dem Programmstart ausgeführt werden.  Näheres  über  die
Verwendung von internal_init, erfahren Sie in der Prozedur selbst. Es sei an
dieser Stelle nur erwähnt,  da₧ die Prozedur "internal_init"  nur  dann  zur
Ausführung gelangt, wenn die Bit-Variable "init!" auf "TRUE" gesetzt ist.

-Anwendung:
Einige Anregungen zur Verwendung von PD-Scheme

Genau wie Lisp ist Scheme besonders dazu geeignet,  symbolische Aufgaben  zu
bewältigen.  Siehe dazu die Programmbeispiele zur symbolischen Ableitung von
mathematischen Ausdrücken (Datei: "SOURCE\DERIV.SCH"). Ich denke, Sie werden
von der Einfachheit und Klarheit der dortigen Beispiele genauso angetan sein
wie ich es bin.

Haben Sie schon einmal versucht ALLE Primzahlen in einer Liste darzustellen?
 - Sicher nicht.  Dann sollten Sie sich einmal das Beispiel zu den "Streams"
anschauen (Datei: "SOURCE\STREAMS.SCH")

~
Zwecks weiterer Inspiration empfehle ich Ihnen folgendes Buch:

        Structure and Interpretation of
        Computer Programs

        Abelson and Sussman

        The MIT Press

        Massachusetts Institute of Technology
        Cambridge, Massachusetts 02142

Dieses Buch liefert sowohl eine Einführung in die  Sprache  Scheme,  alsauch
fortgeschrittene Anwendungen, wie Erstellen eines Interpretierers oder eines
Compilers in - , und für -  die Sprache Scheme.

~
-Speicherverwaltung:
Der "Garbage-Collector" - GC

Die Aufgabe des GC besteht im wesentlichen darin,  nicht mehr benötigte Zel-
len ausfindig zu machen und in die Liste der freien Zellen  einzufügen.  Der
GC durchläuft folgende Phasen:

        1. Markieren aller noch erreichbaren Zellen.
           Damit ist im wesentlichen das globale "Environment" gemeint.

        2. Aufnehmen der unmarkierten Zellen in die Liste der freien Zellen.

        3. Demarkieren der markierten Zellen.

Wichtig ist noch zu erwähnen,  da₧ der GC nur auf dem 'Top'-Level aufgerufen
werden kann. Das bedeutet, da₧ während des Programmablaufs keine Zellen wie-
der freigegeben werden können.  Deshalb wundern Sie sich nicht, wen Sie sich
des öfteren mit der Fehlermeldung "Out of CONS-Cells" konfrontiert sehen.

-Rekursion:
Rekursion und "Tail"-Rekursion

Nätürlich unterstützt PD-Scheme Rekursionen in jeder Beziehung.  Scheme ohne
Rekursion wäre ja auch so sinvoll wie MODULA ohne Moduln. Leider versteht es
PD-Scheme nicht "Tail"-Rekursive Funktionen zu erkennen und  dementsprechend
Speicherplatz zu sparen ( zur Erinnerung : Ein sogennanter "Tail"-rekursiver
Aufruf steht als letzte Anweisung vor der Terminierung einer Funktion, soda₧
es nicht notwendig ist, vor dem rekursiven Aufruf irgendwelche Werte zu ret-
ten. Ein Beispiel:

        (define (counter n)
          (print n)             ; drucke n
          (counter (1+ n)))     ; "Tail"-rekursiver Aufruf

Bei diesem Beispiel sollte zu erkennen sein, da₧ der Wert von n nach dem re-
kursiven Aufruf nicht mehr benötigt wird.  Deshalb wäre es auch nicht nötig,
ein neues "Environment" zu erzeugen. ) (* of zur Erinnerung : *)

-Debuging:
Möglichkeiten der Fehlerbehandlung und Fehlersuche

Neben den Standard-Scheme Funktionen "trace" und "break" existieren  in  PD-
Scheme auch die Funktionen "debug" und "invariant". Mit der Funktion "debug"
können Sie,  an jeder Stelle Ihres Programmtextes,  relevante Werte ausgeben
( z.B. die aktuellen Parameter o.ä. ).  Damit Sie die ständige Ausgabe nicht
belästigt,  wenn Sie sie gerade nicht benötigen,  können Sie mit dem  Befehl
"debug-off" die Ausgabe unterdrücken und mit "debug-on" entsprechend  wieder
einschalten.  Haben sie Ihre Quelltexte als guter Programmierer mit "debug"-
Anweisungen übersät, kann dies vieleicht manchmal des Guten zuviel sein.  Um
dies zu vermeiden,  können Sie die "debug"-Anweisungen mit sogenannten  "Le-
vels" versehen.  Damit können Sie dann ganz gezielt z.B. nur Prozeduren  der
höchsten Abstraktionsebene 'debugen'.
Die Funktion "invariant" können Sie ähnlich wie "debug"  beliebig  in  Ihren
Quelltexten verteilen. Die Argumente der Funktion "invariant" müssen bei je-
dem Aufruf einen Wert ungleich nil ergeben, ansonsten wird eine entsprechen-
de Fehlermeldung ausgegeben. 

Beispiel:       (define (f n)
                  ; Debuging Definitionen
                  (invariant (number? n)) ; stellt sicher, da₧ n Zahl ist
                  (debug top-level "Wert von n :" n)
                  ; Eigentlicher Programmtext
                  (if (zero? n)
                      1          
                      0))                       -->f
                (f 3)                           -->Wert von n :3
                                                   0
                (debug-off)                     -->nil
                (f 3)                           -->0
                (f 'a)                          -->"ERROR" ; invariant
                                                           ; doesn't match

. debug invariant trace break

-debug:
(debug <level> <expr1> <expr2> ...)
(debug <expr1> <expr2> ...)

Evaluiert das erste Argument zu einer Zahl,  wird diese Zahl als Debug-Level
des gesamten Ausdruckes betrachtet.  Das bedeutet, falls das Debuging einge-
schaltet ist und der aktuelle Debug-Level grö₧er oder  gleich  <level>  ist,
werden die Ausdrücke <expr1> <expr2> ... der Reihe nach ausgewertet und über
den Debug-Ausgabeport  ausgegeben  ( siehe "set-debugout!" )
Evaluiert das erste Argument nicht zu einer Zahl,  so werden bei eingeschal-
tetem Debuging die Ausdrücke <expr1> <expr2> ...  ohne Berücksichtigung  des
Debug-Levels ausgegeben.

. debuging debug-on debug-off set-debuglevel! set-debugout!

-debug-on:
(debug-on)

Schaltet das Debuging ein.

. debug debug-off

-debug-off:
(debug-off)

Schaltet das Debuging aus.

. debug debug-on

-set-debuglevel!:
(set-debuglevel! <num>)

Setzt den aktuellen Debug-Level auf den Wert von <num>.  Das  bedeutet,  da₧
nur diejenigen "debug"-Ausdrücke ausgeführt werden, deren Level kleiner oder
gleich <num> ist. 

. debug

-set-debugout!:
(set-debugout! <port>)

<port> spezifiziert den Ausgabeport für die Debuging-Ausdrücke.  Standardmä-
₧ig ist dies der Bildschirm.

. debug outfile

-invariant:
(invariant <expr1> <expr2> ...)

<expr1> <expr2> ... werden von links nach rechts evaluiert. Sobald der erste
Ausdruck den Wert nil annimmt,  wird die laufende Berechnung mit einer  Feh-
lermeldung ( "Invariant doesn't match" ) abgebrochen.

. debuging invariant-on invariant-off

-invariant-on:
(invariant-on)

Schaltet die Überprüfung der "invariant"-Ausdrücke ein.

. invariant invariant-off

-invariant-off:
(invariant-off)

Schaltet die Überprüfung der "invariant"-Ausdrücke aus.

. invariant invariant-on

-set-errorout!:
(set-errorout! <port>)

<port> spezifiziert den Ausgabeport für die Fehlerausgabe. Standardmä₧ig ist
dies der Bildschirm.

. outfile

-Property-Tables:
Eigenschaftstabellen

Mit Hilfe der Prozeduren "put" b.z.w. "get" können Sie Scheme-Objekte in ei-
ner zweidimensionalen Tabelle ablegen b.z.w. auslesen.  Eine häufige  Anwen-
dung einer solchen Tabelle ist das Ablegen  typspezifischer  Funktionen  zur
Unterstützung generischer Operationen ( ?!? ).  Zur Erläuterung,  generische
Operatoren, sind Funktionen wie z.B. "+" oder "*",  die für verschiedene Da-
tentypen definiert sind. Eine sogenannte "Property-Table" könnte  folgender-
ma₧en aufgebaut werden:

                (put '+ 'normal  +_normal)      -->+_normal
                (put '+ 'komplex +_komplex)     -->+_komplex
                (put '* 'normal  *_normal)      -->*_normal
                (put '* 'komplex *_komplex)     -->*_komplex

~
Wobei +_normal die typspezifische Addition  für  "ganz normale"  Zahlen  und
+_komplex die typspezifische Addition für "komplexe" Zahlen ist u.s.w.
Weiterhin gebe es eine Funktion "type?", die den jeweiligen Typ eines Objek-
tes zurückgibt. Mit Hilfe obiger Tabelle kann man nun folgende generische O-
perationen definieren:

                (define (+_all a b)
                  (if (eq? (type? a)
                           (type? b))
                      ((get '+ (type? a)) a b)
                      (error "in +_all, ungleiche Typen" a b)))
                                                -->+_all
                (define (*_all a b)
                  (if (eq? (type? a)
                           (type? b))
                      ((get '* (type? a)) a b)
                      (error "in *_all, ungleiche Typen" a b)))
                                                -->*_all
~
Die Operationen "+_all" und "*_all" arbeiten nun klaglos mit Argumenten  der
Typen "normal" und "komplex".  Der Vollständigkeit wegen seien hier noch die
Konstruktoren "make-normal" und "make-komplex",  das  Prädikat  "type?"  und
stellvertretend für die typspezif. Operationen die Funktionen "+_normal" und
"+_komplex" aufgeführt:

                (define (make-normal num)
                  (list 'normal num))           -->make-normal
                (define (make-komplex real img)
                  (list 'komplex real img))     -->make-komplex
                (define (type? obj)
                  (car obj))                    -->type?
                (define (+_normal a b)
                  (invariant (eq? (type? a) 'normal)
                             (eq? (type? b) 'normal))
                  (list 'normal
                        (+ (cadr a) (cadr b)))) -->+_normal
~
                (define (+_komplex a b)
                  (invariant (eq? (type? a) 'komplex)
                             (eq? (type? b) 'komplex))
                  (list 'komplex
                        (+ (cadr  a) (cadr  b))
                        (+ (caddr a) (caddr b)))) -->+_komplex

Man beachte die "invariant"-Ausdrücke in den typsp. Prozeduren +_normal  und
+_komplex. Diese stellen eine elegante Art der Typrüfung dar. Liegt ein fal-
scher Typ vor,  erscheint eine entsprechende Fehlermeldung.  Nach  austesten
des Programmes kann man mit dem Befehl "invariant-off" die  Überprüfung  ab-
schalten, um die Abarbeitung zu beschleunigen.

. put get invariant

-put:
(put <key> <prop> <value>)

Legt <value> unter dem Schlüssel <key> und der Eigenschaft <prop>  in  einer
Tabelle ab.

. Property-Tables get clear-prop-table

-get:
(get <key> <prop>)

Liest den Wert des Schlüssels <key> mit der Eigenschaft <prop> aus  der  Ta-
belle.

. Property-Tables put clear-prop-table

-clear-prop-table:
(clear-prop-table)

Löscht die Eigenschaftstabelle.

. Property-Tables put get

-Graphic:
Grafik mit PD-Scheme

Die grafischen Möglichkeiten von PD-Scheme möchte ich  als  eher  bescheiden
bezeichnen. Sie beschränken sich auf die Funktionen: plot, line, box, circle
und ellipse, sowie auf die Prozedur "graphmode".

. plot line box circle ellipse graphmode

-graphmode:
(graphmode <num>)

Setzt den aktuellen Grafikmodus <num>.  <num> kann dabei folgende Werte  an-
nehmen:
                0,1     : Replace 
                2       : Transparent
                3       : Exclusiv-Or
                4       : Invers-Transparent

Siehe GFA-Basic: GRAPHMODE
Alle Grafikbefehle werden im aktuellen Grafikmodus dargestellt.

. graphic plot line box circle ellipse

-plot:
(plot <x> <y>)

Zeichnet an den Koordinaten (<x>,<y>) einen Punkt.

. graphic graphmode

-line:
(line <x1> <y1> <x2> <y2>)

Zeichnet eine Linie von (<x1>,<y1>) nach (<x2>,<y2>).

. graphic graphmode

-box:
(box <x1> <y1> <x2> <y2>)

Zeichnet ein Rechteck mit den Eckpunkten (<x1>,<y1>) und (<x2>,<y2>).

. graphic graphmode

-circle:
(circle <mx> <my> <r>)

Zeichnet einen Kreis mit dem Mittelpunkt (<mx>,<my>) und dem Radius <r>.

. graphic graphmode

-ellipse:
(ellipse <mx> <my> <rx> <ry>)

Zeichnet eine Ellipse mit dem Mittelpunkt  (<mx>,<my>),  dem  X-Achsenradius
<rx> und dem Y-Achsenradius <ry>.

. graphic graphmode

-Strings:
Zeichenketten

Ein String ist eine Folge von Zeichen, eingeschlosen von zwei Anführungszei-
chen >"<.  Strings evaluieren zu sich selbst, sie müssen nicht gequotet wer-
den.

Beispiel:       "Hallo"         -->"Hallo"
                '"Hallo"        -->"Hallo"

-Numbers:
Darstellung von Zahlen

In PD-Scheme werden Zahlen dynamisch erzeugt. Unter dynamischer Erzeugung
von Zahlentypen verstehe ich folgendes:

        Es besteht keine generelle Unterscheidung zwischen den Datentypen
        Integer und Real. Ist eine Zahl als Integer darstellbar, wird sie
        auch als Integer dargestellt. Ist die Zahl hingegen nicht als In-
        teger darstellbar, wird sie automatisch als Real dargestellt. Ein
        Beispiel:
                        1.00 wird intern als Integer dargestellt.
                        2147483650 wird als Real dargestellt, weil sie
                        nicht mehr als 4-Byte Integer darstellbar ist.

Man beachte,  da₧ PD-Scheme NICHT die Scheme-übliche BIGNUM Darstellung  für
ganze Zahlen hat. Der Wertebereich für ganze Zahlen ist auf den Bereich, der
mit 4-Byte Integern darstellbar ist,  beschränkt.  D.h. es werden nur  Werte
von -2147483648 bis +2147483647 als Integer dargestellt.  Grö₧ere oder  auch
kleinere Zahlen werden automatisch ins Realformat umgewandelt.

Zahlen evaluieren zu sich selbst, müssen daher nicht gequotet werden.

. number?

-Vectors:
Vektoren

Ein Vektor ist eine Struktur mit beliebiger, aber fester Anzahl von  Elemen-
ten. Vektoren werden durch die Prozedur "make-vector" erzeugt. Zum Beispiel:

          (define v (make-vector 3 'init))      -->v
          (vector-set! v 2 'two)                -->unspecified
          (vector-set! v 1 'one)                -->unspecified
          (vector-ref  v 0)                     -->init
          (vector-ref  v 1)                     -->one
          (vector-ref  v 2)                     -->two
          (vector-ref  v 3)                     -->"ERROR"
          (vector-length v)                     -->3

. vector? make-vector vector-length vector-ref vector-set!

-Streams:

-empty-stream?:
(empty-stream? <obj>)

Ergibt t falls <obj> ein leerer "Stream" ist, nil sonst. Diese Funktion ent-
spricht in jeder Beziehung der Funktion "null?", gibt also genau dann t zu-
rück, falls <obj> die leere Liste "nil" ist, nil sonst.

. null? nil

-cons-stream:
(cons-stream <obj1> <obj2>)

Die Prozedur "cons-stream" ist vergleichbar mit "cons", nur da₧ <obj2> NICHT
evaluiert wird.  Die einfachste Art,  die Wirkungsweise von "cons-stream" zu
beschreiben, ist die, ein analoges 'Makro' dafür anzugeben:

                (defmacro (my-cons-stream a b)
                  (cons a (delay b)))

. head tail cons delay

-head:
(head <pair>)

Entspricht vollständig der Prozedur "car",  liest das "car"-Feld von <pair>.
Diese Prozedur ist zur Anwendung auf  Streams  gedacht.  Also  verwende  man 
besser "(head <stream>)" anstatt "(car <stream>)".

-tail:
(tail <pair>)

Genau wie "cdr",  nur da₧,  falls das "cdr"-Feld von <pair> ein mit  "delay"
erzeugtes Objekt darstellt,  dieses forciert (mit "force") und zurückgegeben
wird.

Beispiele:    (define (number-gen n)
                (cons-stream n (number-gen (1+ n)))) -->number-gen
                ; Keine Angst, die Berechnung läuft nicht unendlich
                ; weil das zweite Argument von "cons-stream" nicht
                ; evaluiert wird.
              (define nat-numbers (number-gen 1))    -->nat-numbers
                ; Boing !!! Haben Sie bemerkt, da₧ nat-numbers die
                ; Auflistung ALLER natürlichen Zahlen ist ?!?
              nat-numbers                            -->(1 ([Delayed-Obj..])
              (head nat-numbers)                     -->1
              (head (tail nat-numbers))              -->2
              (head (tail (tail nat-numbers)))       -->3
                ; u.s.w bis "unendlich"
              nat-numbers                            -->(1 2 3 ([Delaye..]))

Wie man erkennen kann, wird die Liste der natürlichen Zahlen nur so weit be-
rechnet,  wie es unbedingt nötig ist.  Der gro₧e Vorteil dieser  Darstellung
liegt darin, da₧ man nicht schon vorher eine  obere  Schranke  anlegen  mu₧.

. cons-stream head

-delay:
(delay <expr>)

Wert dieser Prozedur ist ein Objekt,  das den unevaluierten Ausdruck  <expr>
und das zum Zeitpunkt des Aufrufs aktuelle Environment  enthält.  Die  durch
die Prozedur "delay" unterdrückte Evaluierung von <expr> kann mit der Proze-
dur "force" forciert werden.

Beispiele:      (define b 10)                -->b
                (define c 15)                -->c
                (define a (delay (* b c)))   -->a
                (define b 3)                 -->b
                (define c 4)                 -->c
                a                            -->([Delayed-Object: (* b c)])
                (force a)                    -->12
                a                            -->12 ;kein Delayed-Obj. mehr !

-force:
(force <d-obj>)

<d-obj> mu₧ ein mit "(delay <expr>)" erzeugtes Objekt sein. Evaluiert <expr>
in dem Environment, in dem es erzeugt wurde. Weiteres siehe "delay".

. delay

-freeze:
(freeze <expr>)

Ähnlich wie "delay", weiteres siehe "thaw"

. thaw delay

-thaw:
(thaw <f-obj>)

<f-obj> mu₧ ein mit "(freeze <expr>)" erzeugtes Objekt sein.  <expr> wird in
dem Environment evaluiert, in dem es erzeugt wurde. Im Gegensatz zu "force",
wird der durch "thaw" erhaltene Wert NICHT gespeichert, sondern wird bei je-
dem Aufruf von "(thaw <f-obj>)" neu berechnet.

Beispiele:      (define b 3)                    -->b
                (define c 4)                    -->c
                (define a (freeze (* b c)))     -->a
                a                               -->([Thunk-Object: (* b c)])
                (thaw a)                        -->12
                a                               -->([Thunk-Object: (* b c)])
                (define b 4)                    -->b
                (thaw a)                        -->16
                a                               -->([Thunk-Object: (* b c)])

. freeze delay

-Input/Output: Ports:
Ein- und Ausgabe

Um Daten zwischen Scheme und externen Medien auszutauschen,  benutzt  Scheme
sogenannte "Ports". Ein Port kann nur jeweils für Ein- oder Ausgabe geöffnet
werden, niemals gleichzeitig für Ein- und Ausgabe.  Der Standard-Eingabeport
repräsentiert gewöhnlich die Tastatur,  der Standard-Ausgabeport  gewöhnlich
den Bildschirm.  Erzeugt werden Eingabe-Ports durch den Befehl "infile"  und
Ausgabe-Ports durch den Befehl "outfile".  Alle Ports sollten nach  Gebrauch
durch "close" wieder geschlossen werden.

. infile outfile close port? read print file-query

-exit:
(exit)
Verlassen des Interpretierers

Mit dem Kommando "exit" können Sie den Interpretierer verlassen.  Bei diesem
Kommando können die Klammern weggelassen werden.

-vi:
(vi <filename>)
(vi)

Das Argument für dieses Kommando mu₧ ein String sein,  der den  Namen  einer
Datei repräsentiert.  Der Editor wird mit der entsprechenden Datei  aufgeru-
fen.  Nach verlassen des Editors kehrt die Kontrolle zurück zum Interpretie-
rer. Die bearbeitete Datei kann dann geladen werden.  Ab dem zweiten Aufruf,
kann der Dateiname weggelassen werden. Es wird dann automatisch der Dateina-
me des vorherigen Aufrufs verwendet.

Beispiel:       (vi "test")

In diesem Beispiel erweitert der Interpretierer den Dateinamen auf

        "\SOURCE\TEST.SCH"

und ruft damit den Editor auf.

Den voreingestellten Pfadnamen, können Sie mit der Funktion "set-path!" ver-
ändern. Um zu verhindern, da₧ der voreing. Pfadname vorangestellt wird, kön-
nen Sie dem Dateinamen einen 'Backslash' ( "\" ) vorausgehen lassen.

Beispiel:       (vi "\test")

. vil load set-path!

-vil:
(vil <filename>)
(vil)

Genau wie "vi",  nur das die editierte Datei automatisch  nach  beenden  des
Editors geladen wird.

. vi

-set-path!:
(set-path! <name>)

<name> mu₧ ein String sein,  der den Namen des neuen Zugriffspfades für  die
Quelldateien repräsentiert.

Beispiele:      (vi "test")          --> Ruft den Editor mit der Datei:
                                         "\SOURCE\TEST.SCH"
                (set-path! "\WORK\") --> Setzt den Zugriffspfad auf:
                                         "\WORK\"
                (vi "test")          --> Ruft den Editor mit der Datei:
                                         "\WORK\TEST.SCH"
                (vi "\SOURCE\TEST")  --> Ruft den Editor mit der Datei:
                                         "\SOURCE\TEST.SCH"

Im letzten Beispiel erkennt der Interpretierer einen 'Backslash' ( "\" )  im
Dateinamen. Deshalb wird der Standard-Zugriffspfad nicht vorangestellt. Des-
weiteren überprüft der Interpretierer noch das Vorhandensein einer  Dateien-
dung (".???").  Existiert keine, so wird automatisch die Endung ".SCH" ange-
hängt.

. vi load
        

-trace:
(trace <name1> <name2> ...)

Die Argumente müssen Namen von Prozeduren sein. Veranla₧t den Interpretierer
bei jedem Eintritt Informationen über die  Aufrufparameter,  und  bei  jedem
Verlassen, Informationen über den Wert der Prozedur auszugeben. Mit der Pro-
zedur "set-evaltrace!" können Sie bestimmen,  ob die Aufrufparameter bei der
Ausgabe evaluiert werden sollen oder nicht. 

. untrace set-evaltrace! set-traceout!

-untrace:
(untrace <name1> <name2> ...)
(untrace)

Schaltet für die angegebenen Prozeduren den Trace-Modus wieder  aus.  Werden
keine Argumente angegeben,  wird für alle Prozeduren der Trace-Modus  ausge-
schaltet.

. trace

-set-evaltrace!:
(set-evaltrace! <exp>)

Evaluiert <exp> zu nil, werden die Aufrufparamter bei der Traceausgabe NICHT
evaluiert. Ergibt sich ein Wert ungleich nil, werden die Aufrufparameter vor
der Ausgabe evaluiert.

. trace

-set-traceout!:
(set-traceout! <port>)

<port> spezifiziert den Ausgabeport für die Traceausgabe.  Standardmä₧ig ist
dies der Bildschirm.

. trace outfile

-break:
(break <name1> <name2> ...)

Die Argumente müssen Namen von Prozeduren bezeichnen.  Veranla₧t den  Inter-
pretierer beim Eintritt in eine solche Prozedur,  unmittelbar zu stoppen und
einen sogenannten 'break-level' zu betreten. Dort kann der Benutzer das 'En-
vironment' inspizieren. Spezielle Kommandos sind im 'break-level' verfügbar:

        (scheme)        Beendet die Abarbeitung und kehrt zum
                        Interpreter-Top-Level zurück.

        (top)           Genau wie (scheme)

        (continue)      Setzt die Berechnung der unterbrochenen
                        Prozedur fort.

. unbreak onbreak

-unbreak:
(unbreak <name1> <name2> ...)
(unbreak)

Schaltet für die angegebenen Prozeduren den Break-Modus  aus.  Werden  keine
Argumente angegeben, wird für alle Prozeduren der Break-Modus ausgeschaltet.

. break

-set-breakout!:
(set-breakout! <port>)

<port> spezifiziert den Ausgabeport für die Breakausgabe.  Standardmä₧ig ist
dies der Bildschirm.

. break outfile

-scheme:
(scheme)

Siehe "break".

. break

-top:
(top)

Siehe "break"

. break

-continue:
(continue)

Siehe "break"

. break

-onbreak:
(onbreak <proc>)
(onbreak)

<proc> mu₧ eine Prozedur ohne Parameter sein.  Veranla₧t im Falle einer  Un-
terbrechung durch den Eintritt in eine Prozedur mit Break-Status, den Aufruf
der Prozedur <proc>. Nach beenden der Prozedur <proc> wird die ursprüngliche
Berechnung fortgesetzt. Der "Break-Level" wird NICHT betreten.  Wird der Pa-
rameter <proc> weggelassen,  wird der normale "Break"-Ablauf  wieder  herge-
stellt. 

Beispiel:       (break f)           -->T    ; Sei f die identische Abbildung
                (Define (my-break-handler)     
                  (print "Hallo"))  -->my-break-handler
                (onbreak my-break-handler) -->T
                (f 4)               -->"Hallo"
                                       4

Normalerweise wird man natürlich eine sinnvollere Aufgabe für die "onbreak"-
Prozedur finden. Z.B. die Ausgabe des aktuellen Environments o.ä. 

. break

-quote:
(quote <expression>)
'<expression>

Evaluiert zu <expression>.  Diese Notation wird verwendet,  um literale Kon-
stanten zu bezeichnen. Die Notation '<expression> ist eine gebräuchliche Ab-
kürzung von (quote <expression>).

Beispiele:      (quote (+ 1 2))         -->(+ 1 2)
                '(+ 1 2)                -->(+ 1 2)
                (quote a)               -->a
                'a                      -->a
                (quote (quote a))       -->(quote a)
                ''a                     -->(quote a)

-if:
(if <condition> <consequent> <alternative>)
(if <condition> <consequent>)

Als erstes wird <condition> ausgewertet.  Ergibt sich ein Wert ungleich nil,
so wird <consequent> evaluiert dessen Wert gilt als Rückgabewert des  gesam-
ten Ausdruckes. Ergibt die Evaluation von <expression> den Wert nil, so wird
entweder,  wenn der Parameter <alternative> angegeben ist,  dieser evaluiert
und dessen Wert als Rückgabewert für den gesamten  Ausdruck  genommen,  oder
es wird nil als Wert des gesamten Ausdruckes zurückgegeben.

Beispiele:      (if (< 1 2) 'yes 'no)    -->yes
                (if (< 2 1) 'yes 'no)    -->no
                (if (< 1 2) (+ 3 4) 'no) -->7
                (if (< 2 1) (+ 3 4))     -->nil ; <consequent> fehlt

. cond

-cond:
(cond <clause1> <clause2> ...)

Jede Klausel mu₧ eine Liste mit einem oder  mehreren  Ausdrücken  sein.  Der
erste Ausdruck in jeder Klausel wird als  Klauselbedingung  bezeichnet.  Die
Klauselbedingungen werden solange nacheinander ausgewertet bis eine zu einem
Wert ungleich nil evaluiert.  Sobald eine Klauselbedingung zu einem Wert un-
gleich nil evaluiert,  werden alle übrigen Ausdrücke der jeweiligen  Klausel
evaluiert.  Der Wert des gesamten Ausdruckes ist in diesem Fall der Wert des
letzten Ausdruckes der ausgewählten Klausel. Besteht die ausgewählte Klausel
lediglich aus der Klauselbedingung selbst, ist der Wert der Klauselbedingung
gleichzeitig der Wert des gesamten Ausdruckes.

Beispiele:      (cond ((> 1 2) 'greater)
                      ((< 1 2) 'less)))  -->less
                (cond ((> 1 2))
                      ((< 1 2)))         -->t
~

Für den Fall, da₧ keine der Klauselbedingungen zutrifft ist nil der Wert des
gesamten "COND"-Ausdruckes.  Aus diesem Grund können Sie  das  Schlüsselwort
"else" als Klauselbedingung für die letzte Klausel  verwenden, um  sicherzu-
stellen, da₧ spätestens die letzte Klauselbedingung zutrifft.

Beispiel:       (cond ((> 1 1) 'greater)
                      ((< 1 1) 'less)
                      (else    'equal))  -->equal

. if

-and:
(and <expr1> <expr2> ...)

Wertet die Ausdrücke <expr1> <expr2> ... von links nach rechts aus und  gibt
den Wert nil zurück,  sobald der erste Ausdruck zu nil evaluiert.  Die verb-
leibenden Ausdrücke werden dann NICHT mehr evaluiert.  Evaluieren alle  Aus-
drücke zu Werten ungleich nil, ist der Wert des gesamten Ausdruckes t.

Beispiele:      (and (= 2 2) (< 1 2))    -->t
                (and (= 2 2) (< 2 1))    -->nil
                (and (= 2 2) 'a (+ 3 4)) -->t

. or not t nil

-or:
(or <expr1> <expr2> ...)

Wertet die Ausdrücke <expr1> <expr2> ... von links nach rechts aus und  gibt
den Wert t zurück, sobald der erste Ausdruck zu einem Wert ungleich nil eva-
luiert. Die verbleibenden Ausdrücke werden dann NICHT mehr evaluiert. Evalu-
ieren alle Ausdrücke zu nil, ist nil der Wert des gesamten Ausdruckes.

Beispiele:      (or (= 2 2) (< 1 2))     -->t
                (or (= 2 2) (< 2 1))     -->t
                (or (= 2 3) nil (< 1 1)) -->nil

. and not t nil

-sequence:
(sequence <expr1> <expr2> ...)

Wertet die Ausdrücke <expr1> <expr2> ... von links nach rechts aus. Wert des
gesamten Ausdruckes, ist der Wert des letzten Ausdruckes.

Einige Funktionen, wie z.B. lambda oder let, verwenden diese Funktion.

. lambda let

-let:
(let ((var1 <form1>) (var2 <form2>) ...) <expr1> <expr2> ...)

Zuerst werden die Ausdrücke <form1> <form2> .. im aktuellen Environment aus-
gewertet ( in irgendeiner unbestimmten Reihenfolge ).  Danach wird das aktu-
elle Environment erweitert.  In diesem erweiterten Environment  werden  dann
die Variablenbezeichner <var1> <var2> ... an die  Werte  der  entsprechenden
Formen gebunden. In diesem erweiterten Environment werden dann die Ausdrücke
<expr1> <expr2> ... von links nach rechts ausgewertet. Wert des gesamten Aus-
druckes ist der Wert des letzten Ausdruckes.

Beispiele:      (let ((x 1) (y 2))
                     (+ x y))           -->3
                (let ((x 1) (y 2))
                  (let ((foo (lambda (z) (+ x y z)))
                        (x 11))
                       (foo 3)))        -->6

. letrec lambda

-letrec:
(letrec ((<var1> <form1>) (<var2> <form2>) ...) <expr1> <expr2> ...)

Erzeugt eine Erweiterung des aktuellen Environments, in dem die Variablenbe-
zeichener <var1> <var2> ... zunächst an unbestimmte Werte  gebunden  werden.
Danach werden die Formen <form1> <form2> ... in unbestimmter Reihenfolge  e-
valuiert. Dann werden die Werte der Formen an die Variablenbezeichner gebun-
den. Abschlie₧end werden die Ausdrücke <expr1> <expr2> ...  der  Reihe  nach
in dem erweiterten Environment ausgewertet und der Wert des letzten Ausdruk-
kes als Wert des gesamten Ausdruckes zurückgeliefert.

Beispiel:       (let ((x 1) (y 2))
                  (letrec
                       ((foo (lambda (z) (+ x y z)))
                        (x 11))
                       (foo 3)))        -->16

~

Eine Einschränkung von "letrec" gilt es noch zu erwähnen: Die Evaluation je-
der der Formen <form1> <form2> ...  mu₧ ohne Zugriff auf eine der durch  die
Variablenbezeichner <var1> <var2> ... bestimmten Variablen vonstatten gehen.

. let lambda

-set!:
(set! <var> <expr>)

<var> mu₧ eine bereits gebundene Variable sein.  Evaluiert <expr> und bindet
den resultierenden Wert an der Stelle des  Environments  an  <var>,  an  der
<var> bereits gebunden war (was <var> ist mu₧ auch <var> bleiben !!!).  Wert
des gesamten Ausdruckes ist unbestimmt.  Ist <var> im aktuellen  Environment
nicht gebunden,  werden alle untergeordneten Environments nach einer Bindung
von <var> durchforstet.  Ist auch dort keine Bindung zu  finden,  wird  eine
entsprechende Fehlermeldung ausgegeben ( "unbound variable <var>" ).  "set!"
hat keinen bestimmten Wert und wird nur wegen des Seiteneffektes aufgerufen.

Beispiel:       (let ((x 1))
                     (set! x (+ x 7))
                     x)                 -->8

-lambda:
(lambda (<var1> <var2> ...) <expr>)

Die Ausdrücke <var1> <var2> ... müssen Symbole sein.  Der  "lambda"-Ausdruck
evaluiert zu einem Prozedur-Objekt mit der formellen Parameterliste  (<var1>
<var2> ...) und dem Rumpf <expr>.

WICHTIG: Das zum Zeitpunkt der Auswertung aktuelle Environment wird als Teil
         des Prozedur-Objektes gespeichert. Wenn die Prozedur später mit ak-
         tuellen Parametern aufgerufen wird,  wird das gespeicherte Environ-
         ment um die Bindungen der aktuellen an die formalen  Parameter  er-
         weitert,  wobei die aktuellen Parameter im Aufrufenvironment evalu-
         iert werden. (* Bitte falls nötig mehrmals lesen. *) 
         In diesem erweiterten Environment wird der Ausdruck  <expr>  evalu-
         iert und dessen Wert gilt als Rückgabewert des Prozeduraufrufs.

~
(lambda (<var1> <var2> ...) <expr1> <expr2> ...) 

  kann als Abkürzung für den Ausdruck

(lambda (<var1> <var2> ...) (sequence <expr1> <expr2> ...))

verwendet werden.

Beispiele:      (lambda (x) (+ x 2))        -->[LAMBDA: (X) | (+ X 2)]
                ((lambda (x) (+ x 2)) 4)    -->6
                (let ((x 1) (y 2))
                  ((lambda (x) (+ x y)) 4)) -->6

. define sequence procedure?

-define:
1. Version: (define <var> <expr>)
2. Version: (define (<var> <var1> <var2> ...) <expr1> <expr2> ...)

"define" wird normalerweise auf dem Top-Level verwendet.

Zunächst die Beschreibung der ersten Version:

  Ist <var> im aktuellen Environment gebunden,  wird der Wert des Ausdruckes
  <expr> neuer Wert der Variablen <var>.  Besteht keine Bindung an <var>, so
  wird im aktuellen Environment eine neue Bindung von <var> an den Wert  von
  <expr> erzeugt.  Der Wert des gesamten Ausdruckes ist <var>,  der Name der
  gebundenen Variable.

  Beispiele:    (define plus +)         -->plus
                plus                    -->+
                (define one 1)          -->one
                one                     -->1
                (plus one one)          -->2

~
  Wird "define" am Anfang des Rumpfes eines Prozedur-Objektes  (z.B. lambda)
  aufgerufen, bezeichnet man dies im Gegensatz zur oben beschriebenen Anwen-
  dung,  als lokale Definition. Der Bereich einer solchen lokalen Definition
  ist dann auf den Rumpf des Prozedur-Objektes beschränkt.  Man beachte, da₧
  auch "let" und "letrec" als Prozedur-Objekte angesehen werden können.

  Beispiel:     (let ((x 1) (y 2))
                  (define foo   (lambda (z) (+ x y z)))
                  (define foo+1 (lambda (a) (1+ (foo a))))
                  (foo+1 3))            -->7

~
Beschreibung der zweiten Version:

  Die zweite Version wird häufig als Abkürzung für den Ausdruck:

            (define var (lambda (var1 var2 ...) expr1 expr2 ...)

  verwendet. Diese Möglichkeit ist meiner Meinung nach wesentlich handlicher
  als die Zuweisung eines "lambda"-Ausdruckes an eine Variable.

  Beispiel:      (define (fac n)           ; die gute alte Fakultätsfunktion
                  (if (zero? n)
                      1
                      (* n (fac (-1+ n)))))
                 -->fac
                        
. lambda set! let letrec zero? -1+

-macro:
(macro (<var1> <var2> ...) <expr1> <expr2> ...)

Prinzipiell wie "lambda",  nur das die Aufrufparameter nicht Evaluiert  wer-
den sondern entsprechend Ihrer Bindungen an die formalen Parameter im  Rumpf
des "macro"-Ausdruckes eingesetzt werden. Der so ersetzte  Rumpf  wird  dann
evaluiert. Die oben beschriebene Ersetzung können Sie auch explizit mit Hil-
fe der Prozedur "macroexpand" durchführen.  Der Aufruf eines Makros entspri-
cht daher dem Aufruf der Prozedur "eval" mit dem expandierten Ausdruck.

Beispiele:      (define my-if (macro (condition consequent alternative)
                                (cond (condition consequent)
                                      (else      alternative))))
                            -->my-if
                (macroexpand '(my-if (< 1 2) 'kleiner 'grö₧ergleich))
                            -->(cond ((< 1 2) 'kleiner)
                                     (else    'grö₧ergleich))
                (my-if (< 1 2) 'kleiner 'grö₧ergleich)
                            -->kleiner

Makros werden meistens zur Implementierung sogenannter "special-forms"  ver-
wendet, bei denen nicht alle Aufrufparameter evaluiert werden dürfen.  Genau
wie für "lambda" gibt es auch für "macro" eine Abkürzung - "defmacro".

. defmacro lambda

-defmacro:
(defmacro (<var> <var1> <var2> ...) <expr1> <expr2> ...)

dient als Abkürzung für 

(define <var> (macro (<var1> <var2> ...) <expr1> <expr2> ...)

Siehe "macro"

. macro

-macroexpand:
(macroexpand <expr>)

Expandiert den Makroaufruf <expr>. Weiteres siehe "macro".

. macro

-procedure?:
(procedure? <obj>)

Ergibt t falls <obj> eine Prozedur ist, nil sonst.

. lambda macro arguments binding body

-arguments:
(arguments <proc>)

Liefert die Liste der formalen Parameter der angegebenen Prozedur <proc>.

Beispiel:       (define (f a b)
                  (if (= a b)
                      'gleich
                      'ungleich))     -->f
                (arguments f)         -->(A B)
                (body f)              -->(if (= a b) 'gleich 'ungleich)
                (binding f)           --> ;"Ausgabe des globalen Environ-
                                          ; ments, da f dort gebunden wurde"

. binding body procedure? lambda macro

-binding:
(binding <proc>)

Liefert das zur Prozedur <proc> gehörige Environment.
Näheres siehe "arguments".

. arguments body lambda macro

-body:
(body <proc>)

Liefert den zur Prozedur <proc> gehörigen Rumpf.
Näheres siehe "arguments".

. arguments binding

-nil:
nil

Das Literal nil bezeichnet zum einen den bool'schen Wert "FALSE",  zum ande-
ren die leere Liste.  nil ist selbst-evaluierend, es mu₧ nicht gequoted wer-
den.

Beispiele:      nil     -->nil
                'nil    -->nil

. t null?

-t:
t

Das Literal t steht für den bool'schen Wert "TRUE".  t  ist  selbst-evaluie-
rend, es mu₧ nicht gequotet werden.

Beispiele:      t       -->t
                't      -->t

.nil

-not:
(not <obj>)

Ergibt t falls <obj> den Wert nil hat, nil sonst.

-eq?:
(eq? <obj1> <obj2>)

Ergibt t falls <obj1> in jeder Hinsicht <obj2> entspricht, sonst nil.  Falls
der Benutzter die beiden Objekte auf irgendeine  Weise  unterscheiden  kann,
liefert "eq?" den Wert nil.

Beispiele:      (eq? 'a 'a)        -->t
                (eq? 'a 'A)        -->t    ; PD-Scheme unterscheidet bei
                                           ; Symbolen keine Gro₧-/Klein-
                                           ; schreibung.
                (eq? 'a 'b)        -->nil
                (eq? '(a) '(a))    -->nil  ; Der Interpretierer erzeugt
                                           ; zwei verschiedene Listen
                (eq? "a" "a")      -->t
                (eq? 104 104)      -->t
                (eq? 1.3 1.4)      -->nil
                (eq? (cons 'a 'b)          
                     (cons 'a 'b)) -->nil

. =

-cons:
(cons <obj1> <obj2>)

Diese Funktion fordert von der Speicherverwaltung eine freie  Zelle  an  und
setzt das "CAR"-Feld der Zelle auf <obj1> und das "CDR"-Feld auf <obj2>. Der
Wert des "CONS"-Ausdruckes ist die neu erzeugte Zelle.

Beispiel:       (cons 'a 'b)            -->(a . b)
                (cons 'a nil)           -->(a)
                (cons 'a '(b))          -->(a b)
                (cons 'a '(b c))        -->(a b c)
                (cons 'a (cons 'b 'c))  -->(a b . c)

~
Der Ausdruck

(cons <obj1> <obj2> <obj3> ...)

kann als Abkürzung für 

(... (cons (cons  <obj1> <obj2>) <obj3>) ...)

eingesetzt werden.

Beipiel:       (cons 'a 'b 'c 'd)      -->(((a . b) . c) . d)

. list

-car:
(car <pair>)

Gibt den Wert des "CAR"-Feldes von <pair> zurück. Ist <pair> keine Zelle, so
wird eine entsprechende Fehlermeldung ausgegeben.

Beispiele:      (car '(a . b))          -->a
                (car (cons 'a 'b))      -->a

. cons cdr c....r

-cdr:
(cdr <pair>)

Gibt den Wert des "CDR"-Feldes von <pair> zurück. Ist <pair> keine Zelle, so
wird eine entsprechende Fehlermeldung ausgegeben.

Beispiele:      (cdr '(a . b))          -->b
                (cdr (cons 'a 'b))      -->b

. cons car c....r

-c....r:
(c....r <obj>)

Da in Scheme oft Zugriffe auf die verschieden Elemente einer Liste  erfolgen
und diverse Schachtelungen von "car" und "cdr" nicht besonders übersichtlich
sind,  bietet PD-Scheme die Möglichkeit bis zu  4 "car-cdr"-Ausdrücke  durch
einen Einzigen zu ersetzen.  Dabei beginnt und endet diese  Ersetzung  genau
wie die Prozeduren "car" und "cdr" mit 'c' und 'r'. Dazwischen steht für je-
den Aufruf von "car" ein 'a' und für jeden Aufruf von "cdr" ein  'd'.  Lange
Rede einleuchtendes Beispiel:

                (define a '(1 2 3 4))           -->a
                (car a)                         -->1
                (cadr a)                        -->2
                (caddr a)                       -->3
                (cadddr a)                      -->4
                (define b '(1 (2 3) 4))         -->b
                (car b)                         -->1
                (caadr b)                       -->2
                (cadadr b)                      -->3
                (caddr b)                       -->4

. car cdr

-set-car!:
(set-car! <pair> <obj>)

Ersetzt das "CAR"-Feld von <pair> durch <obj>.  Ist <pair> keine  Zelle,  so
erscheint eine entsprechende Fehlermeldung. Diese Prozedur sollte mit gro₧er
Sorgfalt angewendet werden, da sie äu₧erst verwirrend sein kann. Wert dieser
Prozedur ist die veränderte Zelle <pair>.

Beispiel:       (set-car! '(a b) 'c)    -->(c b)

. car cons

-set-cdr!:
(set-cdr! <pair> <obj>)

Ersetzt das "CDR"-Feld von <pair> durch <obj>.  Ist <pair> keine  Zelle,  so
erscheint eine entsprechende Fehlermeldung. Diese Prozedur sollte mit gro₧er
Sorgfalt angewendet werden, da sie äu₧erst verwirrend sein kann. Wert dieser
Prozedur ist die veränderte Zelle <pair>.

Beispiel:       (set-cdr! '(a b) 'c)    -->(a . c)

. cdr cons

-null?:
(null? <obj>)

Ergibt t falls <obj> die leere Liste "nil" ist, nil sonst.

Beispiele:      (null? nil)     -->t
                (null? '())     -->t    ; nil und () sind identisch.
                (null? 'A)      -->nil
                (null? '(a b))  -->nil

. nil

-atom?:
(atom? <obj>)

Ergibt t falls <obj> keine "CONS"-Zelle ist, nil sonst.

Beispiele:      (atom? nil)             -->t   ; nil ist leere Liste und Li-
                                               ; teral "FALSE"
                (atom? 'a)              -->t   ; Symbole,
                (atom? "a")             -->t   ; Strings und
                (atom? 2)               -->t   ; Zahlen sind Atome
                (atom? (cons 'a 'b))    -->nil

. nil cons

-list:
(list <obj1> <obj2> ...)

Ergibt als Wert eine Liste der Argumente. 

(list <obj-1> <obj-2> ... <obj-n>)

kann als Abkürzung für

(cons <obj-1> (cons <obj-2> ... (cons <obj-n> nil)...))

betrachtet werden.

Beipiele:       (list)                  -->nil
                (list 'a)               -->(a)
                (list 'a 'b)            -->(a b)
                (cons 'a (cons 'b nil)) -->(a b)
                (list 'a 'b 'c)         -->(a b c)
                (list 'a (+ 2 3) 'c)    -->(a 5 c)

. cons list*

-list*:
(list* <obj1> <obj2> ...)

Ähnlich wie "list", nur wird kein abschlie₧endes nil an die Liste angehängt.
Also ist

(list* <obj-1> <obj-2> ... <obj-n-1> <obj-n>)

eine Abkürzung für :

(cons <obj-1> (cons <obj-2> ... (cons <obj-n-1> <obj-n>)...))


Beipiele:       (list*)                 -->"ERROR"
                (list* 'a)              -->a
                (list* 'a 'b)           -->(a . b)
                (cons 'a 'b)            -->(a . b)
                (list* 'a 'b 'c)        -->(a b . c)
                (list* 'a (+ 2 3) 'c)   -->(a 5 . c)

. list cons

-append:
(append <list-1> <list-2> ... <obj>)

Alle bis auf das letzte Argument müssen Listen sein. Das letzte Argument ist
beliebig. Liefert die Liste, die durch Aneinanderhängen aller Argumente ent-
steht. Bei jeweiligem Weglassen der äu₧eren Klammern. Alle bis auf das letz-
te Argument werden zu diesem Zweck kopiert.

Beispiele:      (define a '(a b c))             -->a
                (define b '(d e f))             -->b
                (append a b a)                  -->(a b c d e f a b c)
                a                               -->(a b c)
                b                               -->(d e f)
                (append a 'd)                   -->(a b c d)
                (append a nil b)                -->(a b c d e f) ; nil = ()
                (append 'a b)                   -->"ERROR" ; 'a keine Liste

. append! list

-append!:
(append! <list-1> <list-2> ... <obj>)

Alle bis auf das letzte Argument müssen Listen sein. Das letzte Argument ist
beliebig. Liefert die Liste, die durch Aneinanderhängen aller Argumente ent-
steht.  Bei jeweiligem Weglassen der äu₧eren Klammern.  Die Argumente werden
NICHT kopiert.  Deshalb ist bei der Verwendung dieser Prozedur höchste  Vor-
sicht geboten. ( !!! Warnung vor Zirkulären Listen !!! )

Beispiele:      (define a '(a b c))             -->a
                (define b '(d e f))             -->b
                (append! a b)                 -->(a b c d e f)
                a                               -->(a b c d e f) ; !!!
                b                               -->(d e f)
                (append! a 'd)                  -->(a b c d e f . d)
                (define a '(a b c))             -->a
                (append! a nil b)               -->(a b c d e f) ; nil = ()
                (append! 'a b)                  -->"ERROR" ; 'a keine Liste
                (append! a a)                   -->(a b c a b c a ...) ; !?!
                                                  
Vor Konstruktionen wie der Letzten, kann ich nur ausdrücklich warnen.  Dabei
entstehen zirkuläre Listen,  die den Interpretierer ganzschön ins  Schwitzen
bringen können. Möglicherweise CDR't er solange durch die Liste, bis ihm der
Stack 'überläuft'. - Also Vorsicht !

. append list

-replace:
(replace <list> (<sym-1> <sym-2> ...) (<expr-1> <expr-2> ...))

Der Wert dieser Prozedur ist die Liste <list> nach  Ersetzen  aller  Symbole
<sym-1> <sym-2> ... durch die Werte der Ausdrücke <expr-1> <expr-2> ... .

Beispiele:      (define a '(a b c))         -->a
                (replace a '(a c) '(1 3))   -->(1 b 3)
                a                           -->(a b c) ; a ist unverändert !
                (replace '(a c x (a a b) d e))
                         '(a b c d e f g)
                         '(1 2 3 4 5))      -->(1 3 x (1 1 2) 4 5)
                ; überschü₧ige Ausdrücke werden ignoriert !

. replace!

-replace!:
(replace! <sym> (<sym-1> <sym-2> ...) (<expr-1> <expr-2> ...))

Der Wert dieser Prozedur ist die Liste <sym>  nach  Ersetzen  aller  Symbole
<sym-1> <sym-2> ... durch die Werte der Ausdrücke <expr-1> <expr-2> ... .
Gleichzeitig wird <sym> an die resultierende  Liste  gebunden.  Deshalb  mu₧
<sym> ein Symbol sein.

Beispiele:      (define a '(a b c))         -->a
                (replace! a '(a c) '(1 2))  -->(1 b 3)
                a                           -->(1 b 3) ; a ist verändert !
                (replace! '(a b c)
                          '(a c)
                          '(1 2))           -->"ERROR" ;'(a b c) kein Symbol

. replace

-symbol?:
(symbol? <obj>)

Ergibt t falls <obj> ein Symbol ist, nil sonst.

Beipiele:       (symbol? nil)           -->t
                (symbol? t)             -->t
                (symbol? 'abc)          -->t
                (symbol? 2)             -->nil
                (symbol? '(a b))        -->nil

. t nil

-explode:
(explode <symbol>)

Gibt eine Liste aller Zeichen des Symboles  <symbol>  zurück.  Ist  <symbol>
kein Symbol, erscheint eine entsprechende Fehlermeldung.

Beispiele:      (explode nil)           -->(n i l)
                (explode 'abc)          -->(a b c)
                (explode '(a))          -->"ERROR"  ; (a) ist kein Symbol

. implode symbol?

-implode:
(implode list)

Gibt ein Symbol zurück, dessen Name aus den Namen der Elemente der Liste ge-
bildet wird.  Die Namen der Elemente der Liste müssen genau ein Zeichen lang
sein.  Ist dies nicht der Fall, wird eine entsprechende Fehlermeldung ausge-
geben.

Beispiele:      (implode '(n i l))      -->nil
                (implode '(a b c))      -->abc
                (implode '(a bc d))     -->"ERROR"

. explode symbol?

-number?:
(number? <obj>)

Ergibt t falls <obj> eine Zahl ist, nil sonst.

Beispiele:      (number? 1)             -->t
                (number? 1.23)          -->t
                (number? 1.3e44)        -->t
                (number? nil)           -->nil
                (number? 'one)          -->nil
                (define one 1)          -->one
                (number? one)           -->t
                (number? 'one)          -->nil ; 'one is still a symbol

. numbers

-zero?:
(zero? <num>)

Ergibt t falls <num> Null ist, nil sonst.

Beispiele:      (zero? 0)       -->t
                (zero? 5)       -->nil
                (zero? -3.3)    -->nil

-=:
(= <obj1> <obj2> ...)

Evaluiert das erste Objekt <obj1> zu einer Zahl, dann müssen alle Objekte zu
Zahlen evaluieren. In diesem Fall ist der Wert des gesamten Ausdruckes genau
dann t, falls alle Werte gleich sind, nil sonst.
Evaluiert das erste Objekt <obj1> zu irgend einem Objekt, das keine Zahl ist
hat die Funktion "=" nur ZWEI Parameter.  Der Wert des  gesamten  Ausdruckes
ist t, falls <obj1> und <obj2> gleich sind, nil sonst. Mit Gleichheit ist in
diesem Fall nicht die strenge Gleichheit im Sinne von "eq?" gemeint, sondern
eine Gleichheit im Sinne von "sieht genauso aus wie ?".

Beispiele:      (= 'a 'a)          -->t
                (= 'a 'A)          -->t    ; Symbols are allways uppercase
                (= 'a 'b)          -->nil
                (= '(a) '(a))      -->t    ; (eq? '(a) '(a)) -->nil
                (= (cons 'a 'b)            ; (eq? (cons 'a 'b)
                   (cons 'a 'b))   -->t    ;      (cons 'a 'b)) --> nil

. eq?

-<:
(< <num1> <num2>)

Ergibt t falls <num1> kleiner als <num2> ist, nil sonst.

. = > <=

->:
(> <num1> <num2>)

Ergibt t falls <num1> grö₧er als <num2> ist, nil sonst.

. = < >=

-<=: =<:
(<= <num1> <num2>)
(=< <num1> <num2>)

Ergibt t falls <num1> kleiner/gleich <num2> ist, nil sonst.

. < =

->=: =>:
(>= <num1> <num2>)
(=> <num1> <num2>)

Ergibt t falls <num1> grö₧er/gleich <num2> ist, nil sonst.

. > =

-<>: ><:
(<> <num1> <num2>)
(>< <num1> <num2>)

Ergibt t falls <num1> ungleich <num2> ist, nil sonst.

. = < >

-even?:
(even? <num>)

Ergibt t falls <num> eine gerade Zahl ist, nil sonst.

. odd?

-odd?:
(odd? <num>)

Ergibt t falls <num> eine ungerade Zahl ist, nil sonst.

. even?

-min:
(min <num1> <num2> ...)

Ergibt das Minimum der Zahlen <num1> <num2> ... .

. max

-max:
(max <num1> <num2> ...)

Ergibt das Maximium der Zahlen <num1> <num2> ... .

.min

-1+:
(1+ <num>)

Ergibt die Zahl, die um 1 grö₧er ist als <num>.

. -1+

--1+:
(-1+ <num>)

Ergibt die Zahl, die um 1 kleiner ist als <num>.

. 1+

-+:
(+ <num1> <num2> ...)

Ergibt die Summe der Zahlen <num1> <num2> ... .

-*:
(* <num1> <num2> ...)

Ergibt das Produkt der Zahlen <num1> <num2> ... .

--:
(- <num>)
(- <num1> <num2> ...)

Die erste Version ergibt das additiv Inverse von <num>.  Die zweite  Version
ergibt den Wert,  den man erhält wenn man von <num1> die Summe aller übrigen
Zahlen abzieht.

Beispiele:      (- 5)           -->-5
                (- 10 1 2 3)    -->4    ; = 10-(1+2+3)
                
-/:
(/ <num>)
(/ <num1> <num2> ...)

Die erste Version ergibt das multiplikativ Inverse  von  <num>.  Die  zweite
Version ergibt den Wert,  den man erhält wenn man <num1> durch  das  Produkt
aller übrigen Zahlen teilt.

Beispiele:      (/ 4)           -->0.25
                (/ 48 2 3 4)    -->2    ; = 48/(2*3*4)

-quotient:
(quotient <num1> <num2>)

Ergibt den Wert der Zahlentheoretischen  Integerdivision  von  <num1>  durch
<num2>.

Beispiele:      (/ 5 4)         -->1.25
                (quotient 5 4)  -->1

. remainder /

-remainder:
(remainder n1 n2)

Ergibt den Rest der Zahlentheoretischen  Integerdivision  von  <num1>  durch
<num2>.

Beispiele:      (/ 20 3)         -->6.666666666667
                (remainder 20 3) -->2                ; 6 * 3 + 2 = 20

. quotient /

-sin:
(sin <num>)

Ergibt den Sinus von <num>.

. cos atan

-cos:
(cos <num>)

Ergibt den Cosinus von <num>.

. sin atan

-atan:
(atan <num>)
(atan <num1> <num2>)

Die erste Version ergibt den Arcustangens von <num>.  Die zweite Version er-
gibt den Arcustangens von <num1> geteilt durch <num2>.

. sin cos

-fac:
(fac <num>)

Berechnet die Fakultät von <num>.

-gcd:
(gcd <num1> <num2> ...)

Berechnet den grö₧ten gemeinsamen Teiler von <num1> <num2> ... .

Beispiele:      (gcd 12 16)             -->4
                (gcd 12 16 18)          -->2
                (gcd 12 16 17)          -->1


-round:
(round <num>)

Ergibt den nächsten ganzzahligen Wert grö₧er oder kleiner als <num>.

. floor ceiling

-floor:
(floor <num>)

Ergibt den nächsten ganzzahligen Wert kleiner <num>.

. round ceiling

-ceiling:
(ceiling <num>)

Ergibt den nächsten ganzzahligen Wert grö₧er <num>.

. round floor

-random:
(random <num>)

Ergibt eine zufällige nicht negative Zahl kleiner als <num>, falls <num> an-
gegeben ist, ansonsten wird irgendeine ganze Zahl, positiv oder negativ, zu-
rückgegeben.

. randomize

-randomize:
(randomize <num>)

Initialisiert den Zufallsgenerator mit dem Wert <num>.

. random

-vector?:
(vector? <obj>)

Ergibt t falls <obj> ein vector ist, nil sonst.

. vectors

-make-vector:
(make-vector <length>)
(make-vector <length> <fill>)

Gibt einen neu generierten Vektor der Länge <length> zurück.  Falls das  op-
tionale Argument <fill> angegeben wird, werden alle Elemente auf <fill> ini-
tialisiert.

. vectors

-vector-length:
(vector-length <vec>)

Ergibt die Anzahl der Elemente von <vec>.  Ist <vec> kein Vektor,  erscheint
eine entsprechende Fehlermeldung.

. vectors

-vector-ref:
(vector-ref <vec> <i>)

Liefert den Wert des <i>-ten Elementes von <vec>.  Der Index i mu₧ eine Zahl
zwischen 0 und (vector-length <vec>) minus 1 sein.

. vectors vector-length

-vector-set!:
(vector-set! <vec> <i> <obj>)

Ersetzt das <i>-te Element des Vektors <vec> durch <obj>.  Der  Rückgabewert
dieser Funktion ist unspezifiziert.

. vectors

-port?:
(port? <obj>)

Ergibt t falls <obj> ein Port ist ( Ein- oder Ausgabe ), nil sonst.

. ports

-infile:
(infile <filename>)

Der Parameter <filename> mu₧ ein String sein der den Namen einer  Datei  re-
präsentiert.  Ergibt einen neuen, zur Eingabe geöffneten Port mit Verbindung
zur angegebenen Datei.

Au₧er der gewöhnlichen Pfadbezeichnung kann <filename> auch folgende Gestalt
haben:  
        "CON:"          : Consol-Port
        "MID:"          : MIDI-Port
        "IKB:"          : Tastatur

. input/output read outfile file-query

-outfile:
(outfile <filename>)

Der Parameter <filename> mu₧ ein String sein der den Namen einer  Datei  re-
präsentiert.  Ergibt einen neuen, zur Ausgabe geöffneten Port mit Verbindung
zur angegebenen Datei.

Au₧er der gewöhnlichen Pfadbezeichnung kann <filename> auch folgende Gestalt
haben:  
        "STD:"          : Standard-Out
        "AUX:"          : Serieller-Port (Drucker)
        "LST:"          : Centronix-Port (Drucker)
        "PRN:"          : Drucker-Port   (entweder Seriell oder Paralell)
        "MID:"          : MIDI-Port
        "VID:"          : Bildschirm

. input/output print infile file-query

-close:
(close <port>)

Schlie₧t den angegebenen Port.

. ports infile outfile

-file-query:
(file-query <default-path>)

Diese Funktion stellt eine Besonderheit von PD-Scheme dar.  Mit Hilfe dieser
Funktion können Sie mittels der Dateiauswahlbox Dateipfade  bestimmen.  Wert
von "file-query" ist ein String, der die ausgewählte Datei repräsentiert.
Der optionale Parameter <default-path> bestimmt den von der  Dateiauswahlbox
angezeigten Pfad ( einschlie₧lich "wildcards" ).

Beispiel:       (file-query)     -->"A:\SOURCE\TEST.SCH"

Was bedeutet, da₧ die Datei "A:\SOURCE\TEST.SCH" innerhalb der Dateiauswahl-
box ausgewählt wurde.

. ports infile outfile

-read:
(read <port>)
(read)

<port> mu₧ ein Eingabekanal sein.  Liest den  Ersten  noch  nicht  gelesenen
Scheme-Ausdruck von dem angegebenen Port  (wobei der gelesene Ausdruck nicht
evaluiert wird). Liegt kein Schemeausdruck vor, wird nil zurückgegeben. Wird
der Parameter <port> weggelassen, wird der Standard-Eingabeport verwendet.

. ports infile

-print:
(print <obj> <port>)
(print <obj>)

<port> mu₧ ein Ausgabeport sein. Gibt <obj> über den Ausgabeport <port> aus.
Abschlie₧end erfolgt noch die Ausgabe eines "Carriage-Return".  Wird der Pa-
rameter <port> weggelassen, wird der Standard-Ausgabeport verwendet.

. princ pretty-print ports outfile

-princ:
(princ <obj> <port>)
(princ <obj>)

Wie "print", nur da₧ die Ausgabe NICHT mit einem zusätzlichen "Carriage-Re-"
turn" abgeschlossen wird.

. print

-pretty-print:
(pretty-print <obj> <port>)
(pretty-print <obj>)

Wie "print", nur wird die Ausgabe je nach Listenstruktur  eingerückt.  Diese
Funktion arbeitet leider nicht ganz so, wie ich es mir wünschen würde,  lä₧t
sich aber denoch gut einsetzen.

. print set-prettyflatten! set-stdpretty!

-set-prettyflatten!:
(set-prettyflatten! <num>)

<num> gibt an,  wie lang ( in der Ausgabezeile ) ein Listenelement sein mu₧,
damit es beim "pretty-printing" in die nächste Zeile genommen wird. Mit die-
ser Option kann man vermeiden,  da₧ Listen wie z.B. (17 23 4 51 9) wie folgt
zerrissen werden: (17 23
                      4
                      51
                      9)

Prettyflatten sollte etwa im Bereich von 3 bis 10 liegen.

. pretty-print

-set-stdpretty!:
(set-stdpretty! <exp>)

Evaluiert <exp> zu einem Wert ungleich nil,  wird  das  sogennante  "pretty-
printing" standardmä₧ig bei "print" und "princ" angewendet.  Evaluiert <exp>
zu nil, wird das Standard-"pretty-printing" ausgeschaltet.

. pretty-print print

-newline:
(newline <port>)
(newline)

Gibt ein "Carriage-Return" über den angegebenen Port aus.  Fehlt der Parame-
ter <port>, wird der Standardausgabeport verwendet.

. print ports

-set-stdout!:
(set-stdout! <port>)

<port> spezifiziert den Ausgabeport für die  Standardausgabe.  Normalerweise
ist dies der Bildschirm.

. print outfile

-set-printbase!:
(set-printbase! <base>)

<base> bestimmt die Basis für die Zahlenausgabe ( nur "Integer" ).  Mögliche
Werte sind:
                2       : Ausgabe binär
                8       : Ausgabe octal
                10      : Ausgabe dezimal
                16      : Ausgabe hexadezimal

Wert von "set-printbase!" ist immer '10'.  Das liegt daran,  das die Eingabe
<base> jeweils bezüglich der neuen Basis zurückgegeben wird. Eingaben finden
immer zur Basis 10 statt, es sei den Sie stellen den Zahlen folgende Zeichen
voraus:

                %       : Eingabe binär
                ▌       : Eingabe octal
                $       : Eingabe hexadezimal
                sonst   : Eingabe dezimal

Beispiele:      (set-printbase! 16)     -->$10
                $16                     -->$16
                %1010                   -->$A
                (set-printbase! 2)      -->%10
                5                       -->%101

. print

-set-printlength!:
(set-printlength! <num>)

<num> gibt an, wieviele Elemente einer Liste maximal ausgedruckt werden. Die
nachfolgenden Elemente werden durch "..."  angedeutet.  Wird  der  Parameter
<num> weggelassen, dann werden ALLE Listenelemente ausgedruckt.

Beispiele:      (define a '(1 2 3 4 5))         -->a
                (set-printlength! 3)            -->3
                a                               -->(1 2 3 ...)
                (set-printlength! 2)            -->2
                (list a a a a)                  -->((1 2 ...) (1 2 ...) ...)
                (set-printlength!)              -->T
                a                               -->(1 2 3 4 5)

Zur Beschränkung der Schachtelungstiefe siehe "set-printlevel!".

. print set-printlevel!

-set-printlevel!:
(set-printlevel! <num>)

<num> gibt die maximale Schachtelungstiefe von Listen bei  der  Ausgabe  an.
Tieferliegende Unterlisten werden durch "#" angedeutet. Wird <num> wegge-
lassen, dann werden Listen wieder ungekürzt ausgedruckt.

Beispiele:      (define a '(x))                 -->a
                (define b (list a a))           -->b
                (define c (list b b))           -->c
                c                               -->(((x) (x)) ((x) (x)))
                (set-printlevel! 2)             -->2
                c                               -->((# #) (# #))
                (set-printlevel! 1)             -->1
                c                               -->(# #)
                (set-printlevel! 0)             -->0
                c                               -->#               

Zur Beschränkung der Listenlänge, siehe "set-printlength!"

. print set-printlength!

-load:
(load <filename>)

Das Argument mu₧ ein String sein, der den Namen einer Scheme-Datei repräsen-
tiert.  Solange kein Fehler auftritt, werden alle Scheme-Ausdrücke der Datei
nacheinander eingelesen und evaluiert. Beim ersten aufgetretenen Fehler wird
der Ladevorgang abgebrochen. Der Wert dieser Prozedur ist t, falls kein Feh-
ler auftrat, nil sonst.

. load* file-query

-load*:

Genau wie "load",  nur das bei auftreten eines Fehlers der Ladevorgang  beim
nächsten Ausdruck fortgesetzt wird.

. load

-cls:
(cls)

Löscht das Arbeitsfenster.

-the-environment:
(the-environment)

Gibt das aktuelle Environment zurück.  Das aktuelle Environment enthält alle
Variablenbindungen die zu diesem Zeitpunkt sichtbar sind.

. the-global-environment make-environment eval

-the-global-environment:
(the-global-environment)

Gibt das globale, d.h. das "Top-Level" Environment zurück.

. the-environment make-environment eval

-make-environment:
(make-environment <def1> <def2> ...)

Jedes der Argumente sollte ein "define"-Ausdruck sein.  Erweitert das  aktu-
elle Environment um die angegebenen Definitionen <def1> <def2> ...  und gibt
das erweiterte Environment als Wert zurück.

. the-environment eval

-eval:
(eval <expr> <env>)
(eval <expr>)

Wert dieser Prozedur ist der Wert der Evaluierung des Ausdruckes  <expr>  im
Environment <env>.  Wird <env> nicht angegeben, wird <expr> im aktuellen En-
vironment evaluiert.

Beispiele:      (define a 3)                               -->a
                (define e (make-environment (define a 4))) -->e
                (eval 'a (the-environment))                -->3
                (eval 'a)                                  -->3
                (eval 'a e)                                -->4


. make-environment the-environment apply

-apply:
(apply <proc> <args>)

Erfordert, da₧ <proc> eine Prozedur und <args> eine entsprechende Liste  von
Argumenten ist.  Ruft <proc> mit <args> als aktuellen Parametern  auf.  Wert
des gesamten Ausdruckes, ist der Wert der Anwendung von <proc> auf <args>.

Beispiele:      (apply + '(3 4 5))      -->12
                (apply list '(3 4 5))   -->(3 4 5)

. eval

-error:
(error <exp1> <expr2> ...)

Diese Prozedur verursacht bei deren Evaluation einen Fehlerausstieg aus  der
laufenden Berechnung. Die Werte der Parameter <expr1> <expr2> .. werden über
den Standard-Fehlerausgabeport ausgegeben.

. set-errorout!

-runtime:
(runtime)

Liefert die seit Begin der Scheme-Sitzung verstrichene CPU-Zeit in  1/60-tel
Sekunden.

