4.9 KiB
Destructuring und Pattern-Matching in Parameterlisten
Status: Architekturentwurf / Vorbereitung Kontext: Unification ("Everything is a Tuple")
1. Motivation
Bisher mussten Datenstrukturen innerhalb einer Funktion manuell zerlegt werden (z. B. via get). Dies ist nicht nur unhandlich, sondern verhindert auch tiefgreifende statische Optimierungen. Durch die Umstellung von Parameterlisten auf eine einheitliche Tupel-Struktur im AST wird Destructuring ermöglicht.
2. Technische Vorteile
Destructuring ist weit mehr als "Syntactic Sugar". Es ist ein entscheidendes Werkzeug für die Performance der DSL:
2.1 Statische Performance (Zero-Cost Abstraction)
Beim manuellen Zugriff via (get tuple index) muss die VM zur Laufzeit:
- Prüfen, ob das Objekt ein Tupel ist.
- Einen Bounds-Check durchführen.
- Den Wert extrahieren.
Mit Destructuring kennt der Specializer die Struktur bereits beim Kompilieren. Die Werte werden direkt aus dem Eingangs-Tupel in die Stack-Slots (oder Register) kopiert. Es entfallen alle Laufzeit-Checks.
2.2 Monomorphisierung & Unboxing
Wenn eine Funktion (fn [[x y]] ...) mit zwei Floats aufgerufen wird, kann der Spezialisierer eine Version erzeugen, die kein Tupel-Objekt auf dem Heap mehr benötigt. Die Werte werden als flache Sequenz (idealerweise in CPU-Registern) übergeben. Das "Verpacken" in ein Objekt entfällt komplett.
2.3 Statische Shape-Validierung
Der TypeChecker kann bereits zur Compile-Zeit garantieren, dass die übergebenen Daten exakt zum erwarteten Muster passen.
- Beispiel: Erwartet die Funktion ein OHLC-Paket
[o h l c], führt ein Aufruf mit nur drei Werten zu einem Kompilierfehler statt zu einem Absturz zur Laufzeit.
2.4 Grundlage für Pattern Matching
Destructuring bereitet den Weg für Funktions-Overloading basierend auf Daten-Shapes:
(def process
(fn
([x y] (handle-2d x y))
([x y z] (handle-3d x y z))))
3. Anwendungsszenarien
A. Einfaches Unpacking
Direktes Zerlegen von Argumenten in lokale Variablen.
(def add-point (fn [[x y]] (+ x y)))
(add-point [10 20]) ; -> 30
B. Tupel als einzelner Parameter
Soll ein Tupel als Ganzes behandelt werden, wird einfach ein einzelner Name verwendet.
(def sum (fn [data] (reduce + data)))
(sum [1 2 3]) ; 'data' ist das gesamte Tupel
C. Aliasing (:as Binding)
Zerlegen der Struktur, während das Original-Objekt unter einem Namen verfügbar bleibt.
(fn [[x y :as point]]
(do
(log point) ; Zugriff auf das gesamte Tupel [x y]
(+ x y))) ; Zugriff auf Einzelteile
4. Visuelle Repräsentation und AST-Design
In dieser DSL ist der AST kein verstecktes Zwischenprodukt, sondern das primäre Modell, auf dem der visuelle Editor operiert. Die Umstellung auf eine einheitliche Tupel-Struktur ist die fundamentale Voraussetzung für eine konsistente grafische Benutzerführung.
4.1 Visuelle Symmetrie (Shape-Matching)
Da Argumentlisten (Aufruf) und Parameterlisten (Definition) nun dieselbe AST-Struktur besitzen, wird ein Funktionsaufruf visuell zum Ineinanderstecken von Bausteinen:
- Ein Funktions-Knoten hat einen "Eingangs-Port" (das Parameter-Tupel).
- Die übergebenen Daten haben eine "Ausgangs-Form" (das Argument-Tupel).
- Destructuring bedeutet grafisch einfach, dass der Eingangs-Port einer Box intern weiter unterteilt ist. Der User "zeichnet" die Zerlegung der Daten direkt durch die Struktur der Slots.
4.2 Der AST als UI-Modell (Structural Editing)
Da der AST "1st Class Citizen" ist, muss der visuelle Editor keine komplexen textuellen Grammatikregeln für Destructuring verstehen. Er operiert stattdessen auf primitiven strukturellen Operationen:
- Nesting: Ein Slot kann in zwei Sub-Slots unterteilt werden (entspricht dem Umwandeln eines
Parameter-Knotens in einenTuple-Knoten). - Identity Mapping: Da jeder
Parameterim AST eine eindeutigeIdentitybesitzt, kann der Editor eine direkte visuelle Linie (Link) von der Definition zur Verwendung ziehen, ohne auf Namens-Suchen angewiesen zu sein.
4.3 Transparenz der Spezialisierung
Die visuelle Sprache profitiert massiv von der statischen Analyse des Spezialisierers:
- Wenn der User zwei unboxed Floats in ein
[x y]Muster zieht, kann der Editor dies farblich oder form-basiert als "harten Link" (Monomorphisierter Pfad) markieren. - Fehlende Übereinstimmungen (z. B. ein 3er-Tupel in einen 2er-Eingang) werden sofort visuell als "nicht einrastend" oder durch eine Fehlermeldung am Port markiert, noch bevor der Code ausgeführt wird.
5. Implementierungsstatus
Die strukturellen Voraussetzungen im AST (UntypedKind::Parameter, BoundKind::Parameter) und im Typsystem (Signature mit einem StaticType) sind geschaffen. Der Binder und die VM sind auf die Verarbeitung von rekursiven Mustern vorbereitet.