Ein paar Worte vorabHome   Letzte MeldungenNews   Index der Kapitel und der besprochenen FunktionenIndex   Wer ich bin, warum ich diese Seiten mache, KontaktImpressum   Ich freue mich über jeden Eintrag im Gästebuch!Gästebuch   Einige Links zu anderen AutoLisp-SeitenLinks   Copyrights und DisclaimerRechts
Hier können die kompletten Seiten als ZIP-File heruntergeladen werden!

Funktionen für komfortables Arbeiten mit Zeichenketten String-Tango
Noch mehr Funktionen für komfortableres Arbeiten mit Zeichenketten Kettenhunde
strtok zerlegt Zeichenketten anhand eines Trennzeichens Tock-Tock
Arbeiten mit Datum und Zeit in AutoLisp Zeitlos...
Dotted pairs - wie man den Programmabbruch verhindert Gepunktet?
Neue Funktionen für die Listenbearbeitung Strukturtapete
Weitere neue Funktionen für die Listenbearbeitung Listen to me!
Lambda expressions - dasSalz in der Suppe Lambada
Lambda expressions anhand eines Praxisbeispiels Unter der Erde
Where und whereever erleichtern den Umgang mit Listen Quo vadis?
Rekursion - Funktionen, die sich selbst aufrufen Katzenschwanz
Ein äusserst wichtiger Prototyp für Funktionen Nix passiert
Wo das lineare mapcar am Ende ist Tiefer rein!
Über Effekte und Neben(Seiten-)Effekte von Funktionen Seitensprünge
Die Namensräume (Sichtbarkeit) von Variablen Raumwunder
Let dient zur Schaffung kleinerer Namensräume Lass mal...
Sukzessive Verarbeitung von Listenresten mit mapcdr Der Bruder
Was in AutoLisp einfach nicht machbar ist (Teil I) Beschränkt
Was in AutoLisp einfach nicht machbar ist (Teil II) Limited Edition
Nicht mit Effekten arbeiten, sondern direkter Daten-Änderung Destruktiv
Sequenzielles vs. paralleles Abarbeiten von Argumenten Parallelwelten
Über den Umgang mit Funktionsschablonen Erwachet!
Ein Praxiskapitel über Auswahlsätze, Attribute, wcmatch und mehr Durch die Brust
Die Farben des AutoCAD Color Index und ihre RGB-Werte Alles so schön
Hier laufen die Fäden zusammen: Viele Konzepte vereint Lapsus Lispuli
Ein Spiel als Beispiel für lernfähige Funktionen Zug um Zug
Errorhandling in AutoLisp - Teil 1 Alles valsch!
Errorhandling in AutoLisp - Teil 2 Und foll Feler!


Zum Einsteiger-Tutorial

Zu den ActiveX-Seiten

Meine Private HP mit Fotos, Gedichten, Musik und Postkartenversand

Mein Online-Lexikon der Fotografie

Mein völlig abgedrehtes Reisebüro










Funktionen können in Lisp ihre Argumente entweder parallel oder sequenziell abarbeiten. In diesem Kapitel soll der Unterschied zwischen den beiden Arbeitsweisen aufgezeigt werden. Um zunächst einmal klar zu machen, worum es überhaupt geht, werfen wir einen Blick auf die Arbeitsweise von setq:
(setq a 100 b (1+ a)) => 101
                  
Offensichtlich arbeitet setq sequenziell, d.h. die Argumente werden in der Reihenfolge von links nach rechts abgearbeitet, und bei der zweiten durchgeführten Zuweisung kann schon auf das Ergebnis der ersten Zuweisung zugegriffen werden. Wie aber verhält es sich mit selbstgeschriebenen Funktionen in dieser Hinsicht?

Testen wir doch einmal, was unser let da macht. Ein Hinweis: Die Funktion let wird im entsprechenden Kapitel beschrieben, der Inhalt dieses Kapitels sollte bekannt sein. Auch verstanden haben sollte man das, was im Kapitel Namespaces zu finden ist, es könnte hier doch sonst vielleicht nur hilfloses Kopschütteln entstehen.
(let '((a 1)(b (1+ a)))
 '(progn
    (print a)
    (print b)
  )
)   => ???
                  
Nun, hier werden wir uns wahrscheinlich eine Fehlermeldung einhandeln! Deshalb wahrscheinlich, weil ja auch noch eine Variable a mit einem übergeordneten Namensraum existieren könnte, deren Wert für die Zuweisung an b verwendet würde. Testen wir das doch einmal explizit aus - wir setzen noch eine Funktion als äusseren Namensraum um den let-Aufruf herum und schaffen dort eine solche übergeordnete Variable a:
(defun test( / a b c)
  (setq a 100 b 200 c 400)
  (let '( (a 1)
          (b (1+ a))
          (c (1+ b))
        )
    '(list a b)
  )
)
    => (1 101 201)
                 
Nun, dieses Ergebnis war zu vermuten! Schliesslich wird ja die ganze Liste mit den Bindungen für let zuerst evaluiert, und dann wird überhaupt erst der neue Namensraum durch das lambda geschaffen! Bis zu diesem Zeitpunkt liegen die Symbole noch im alten Namensraum, d.h. dem übergordneten der Funktion test.

Können wir hier eine sequenzielle Abarbeitung, wie wir sie bei setq beobachtet haben, erreichen? Natürlich können wir das. Was wir brauchen, ist ein Mechanismus, der die Namensräume etwa so verschachtelt:
(let '((a 1))
 '(let '((b (1+ a)))
   '(let '((c (1+ b)))
     '(list a b c)
    )
  )
)
    => (1 2 3)
                 
In anderen Lisp-Dialekten wird die sequenzielle Version durch einen Stern im Namen gekennzeichnet, sie heisst also let* im Gegensatz zum parallel verarbeitenden let. Was nun noch fehlt, ist die Funktion selbst - hier ist sie schon:
(defun let*(bindings expr / )
  (if(cdr bindings)
    (let
      (list(car bindings))
      (cons 'let*
        (list
          (cons 'quote(list(cdr bindings)))
          (cons 'quote(list expr))
        )
      )
    )
    (let bindings expr)
  )
)
                  
Das sieht auf den ersten Blick nicht sehr aufregend aus, setzt aber doch einen etwas komplizierten Prozess in Gang. Testen wir aber zunächst die Funktion an unserem Beispiel, und zwar wieder innerhalb der Testfunktion:
(defun test( / a b c)
  (setq a 100 b 200 c 400)
  (let* '( (a 1)
           (b (1+ a))
           (c (1+ b))
         )
    '(list a b c)
  )
)
    => (1 2 3)
                  
Aus dem Ergebenis können wir schliessen, dass bei let* jede Variable sofort ihren entsprechenden Namensraum hat. Die namensgleichen übergeordneten Symbole werden verdeckt - in diesem Beispiel spielen sie keine Rolle mehr!

Die Funktion let* arbeitet rekursiv. Die jeweils erste Variablenbindung wird in einen Aufruf von let umgewandelt, ind den ein let* ohne diese erste Bindung eingebettet ist. Hier noch einmal zum besseren Verständnis die Schritte, wie sich der Ablauf vollzieht:
; Der Aufruf
(let* '( (a 1)
         (b (1+ a))
         (c (1+ b))
       )
  '(list a b c)
) => (1 2 3)

;Erstes let aufgelöst
( (lambda (a)
    (let* '( (b (1+ a))
             (c (1+ b))
           )
     '(list a b c)
    )
  )
  1
) => (1 2 3)

;zweites let aufgelöst
( (lambda (a)
    ( (lambda (b)
        (let* '( (c (1+ b)))
         '(list a b c)
        )
      )
      2
    )
  )
  1
) => (1 2 3)

; drittes let aufgelöst
( (lambda (a)
    ( (lambda (b)
        ( (lambda (c)
           '(list a b c)
          )
          3
        )
      )
      2
    )
  )
  1
) => (1 2 3)