Synchronous Dataflow Pattern Matching Christian Cikryt und Jakob Pfender FU Berlin Institut für Informatik Seminar über Programmiersprachen 23. Juli 2013 Einleitung Thema der Arbeit Einführung von varianten Typen ” (Datenstruktur) und Pattern Matching (Kontrollstruktur) in synchrone Datenflusssprachen“ Begriffsdefinitionen Reaktive Systeme ▶ Ständige Interaktion mit der Umgebung ▶ Umgebung gibt die Geschwindigkeit vor ▶ Beispiele: Mikrowellen, Roboter, industrielle Steuerungsanlagen Synchrone Datenflusssprachen ▶ Sprachen für die Entwicklung reaktiver Systeme ▶ Funktionale Programmiersprachen auf unendlichen Datenströmen ▶ Beispiele: LUSTRE, SCADE, SIGNAL Clocks und Clock Calculus Clock ▶ (De)aktiviert Programmteile in synchronen Datenflusssprachen ▶ Repräsentiert Geschwindigkeit eines Ausdrucks ▶ Erlaubt Modellierung paralleler Prozesse mit unterschiedlichen Geschwindigkeiten Clock Calculus ▶ Beweisbar korrekte statische Analysemethode ▶ Für Ausdrücke mit unterschiedlichen Geschwindigkeiten Variante Typen und Pattern Matching ▶ Bekannt aus der funktionalen Programmierung ▶ Variante Typen speichern Werte, der einen von mehreren vordefinierten Typen annehmen kann ▶ Erhöhte Typsicherheit durch Pattern Matching Variante Typen und Pattern Matching – Beispiel type 'a baum = Blatt | Knoten of 'a * 'a baum * 'a baum let rec mitglied x baum = match baum with | Blatt -> false | Knoten(y, links, rechts) -> if x = y then true else member x links || member x rechts;; Motivation und Ziele Mangel an Datenstrukturen ▶ Synchrone Datenflusssprachen unterstützen nur sehr wenige Datentypen (Boolean, ganze Zahlen, Fließkommazahlen, Arrays) ▶ Mit steigender Komplexität reaktiver Systeme steigen auch Anforderungen an die Sprache Mangel an Konstrollstrukturen ▶ Sequentielles oder sich entwickelndes Verhalten funktional auszudrücken ist nicht trivial ▶ Existierende Sprachen haben auf unterschiedlichste Art versucht, Kontrollstrukturen einzuführen ▶ Hier gelöst durch Clock Calculus, Pattern Matching und variante Typen Die Sprache Beispiel type event = Left | Middle | Right let up_down mouse = count where rec count = 0 -> match mouse with | Left on c => (pre count) when c + 1 | Middle => 0 | Right on c => (pre count) when c - 1 Operationelle Semantik von WHEN [] ▶ WHEN-[]: [] R ⊢ e1 − →e′1 R ⊢ e1 R ⊢ e2 − →e′2 [] when e2 − →e′1 c ▶ WHEN-T: R ⊢ e1 → − e′1 R ⊢ e1 when c ▶ WHEN-F: R ⊢ e1 → − e′1 R ⊢ e1 when e′2 true R ⊢ e2 −−→e′2 c e2 − →e′1 when R ⊢ e2 −−→e′2 [] when e′2 false e2 − →e′1 when e′2 Erweitertes Beispiel type event = Left | Right | Middle | Key of int let up_down event = count where rec count, step = (0,1) -> match event with | Left on c => ((pre count) + step, pre step) when c | Middle on c => 0, (pre step) when c | Right on c => ((pre count) - step, pre step) when c | Key i on c => (pre count) when c, i Clocks und Pattern Matching Clocks und Pattern Matching – Beispiel type number = Int of int | Float of float let float_of_number n = match n with | Int i => float i | Float f => f Es gilt: c1 ∧ c2 = false c1 ∨ c2 = cl Eigenschaften der Branch Clocks ▶ Subclocks des gematchten Elements ▶ Gegenseitiger Ausschluss ▶ Genau eine Branch Clock muss verfügbar sein ▶ Pattern Matching vollständig definiert Benennung Explizit mit on-Schlüsselwort: match event with . . . | (Key i) on c => (pre count) when c, i Implizit: pre (x when c) (pre x) when c Zusammenfassen von Ausdrücken: match event, (pre count) with . . . | (Key i), pc => (pc, i) Formalisierung Grammatik e ::= c | x | op(e, e) | c D ::= D and D|D c ::= i | fun x.y with D d ::= x in with fby when e D | x = e | x = e(e) D i ::= true | false | 0 | ... op ::= + | ... e|e Operationelle Semantik v ▶ R⊢e− → e′ ▶ R ⊢ D −→ D′ ▶ R⊢d− → d′ R′ v Formalisierung des Clock Calculus Grammatik: σ ::= ∀α1 , ..., αm .∀K1 , ..., Kk .cl cl ::= cl → cl | s | (k : s) s ::= base | s k ::= x | K Operationelle Semantik: ▶ H ⊢ e : cl ▶ H ⊢ D : H′ ▶ H ⊢ d : cl on k|α n, m, k ∈ N Formalisierung der Erweiterungen Deklaration varianter Typen type (α1 , ..., αm ) t = C1 of τ1 | ... | Cn Grammatik e ::=... | C1 (e) | ... | Cn (e) P ::= c | x | C1 (P) | ... | Cn (P) D ::= x = match e | P1 with on x 1 ⇒ d1 on xn ⇒ dn ... | Pn of τn Formalisierung der Erweiterungen Erweiterung durch Konstruktoren: sv ::= c | C1 (sv) | ... | Cn (sv) v ::= sv | [] Reduktionsregeln: [] R⊢e− → e′ [] R ⊢ Ci (e) −−−→ Ci (e′ ) R⊢e− → e′ R ⊢ Ci (e) − → Ci (e′ ) sv Ci (sv) Reduktionsregeln für Pattern Matching MATCH-[]: [] R, [[]/x] ⊢ e − → e′ [] ∀i ∈ {1, ..., n}R, [[]/x], [[]/xi ], [F/ci ] ⊢ di − → d′i x = match e′ with | P1 (x1 ) on c1 ⇒ d′1 x = match e with | P1 (x1 ) on c1 ⇒ d1 R⊢ ... | Pn (xn ) [[]/x] on cn ⇒ dn −−−→ ... | Pn (xn ) on cn ⇒ d′n Reduktionsregeln für Pattern Matching MATCH: Pj (vj ) R, [v/x] ⊢ e −−−→ e′ v R, [v/x], [vj /xj ], [T/cj ], ⊢ dj → − d′j [] ∀i ∈ {1, ..., n} such that i ̸= j, R, [v/x], [[]/xi ], [F/ci ] ⊢ di − → d′i x = match e′ with | P1 (x1 ) on c1 ⇒ d′1 x = match e with | P1 (x1 ) on c1 ⇒ d1 R⊢ ... | Pn (xn ) [v/x] on cn ⇒ dn −−−→ ... | Pn (xn ) on cn ⇒ d′n Reduktionsregeln für erweiterten Clock Calculus C-H: H⊢e:s H ⊢ C(e) : s MATCH-H: H, [x : cl] ⊢ e : cl ∀i ∈ {1, ..., n} : H, Hi ⊢ Pi : cl on ci H, Hi , [x : cl] ⊢ di : cl ci ∈ / fvcl (H), Dom(Hi ) = fvPi H⊢ x = match e with | P1 (x1 ) on c1 ⇒ d1 ... | Pn (xn ) on cn ⇒ dn : [x : cl] on ci Kritik Probleme bei der Übersetzung Beispielprogramm: match v with | true on c => let rec nat = 0 fby (nat + 1) in (nat when c) | false => 0 Ist äquivalent zu: let rec nat = 0 fby (nat + 1) in match v with | true on c => nat when c | false => 0 Probleme bei der Übersetzung Beispielprogramm: match v with | true on c => let rec nat = 0 fby (nat + 1) in let x = (merge c nat 0) in (x when c) | false => 0 Ist äquivalent zu: let nat, c = match c with | true => let rec nat = 0 fby (nat + 1) in nat, true | false => 0, false in let x = merge c (nat when c) 0 in match v with | true => x when c | false => 0 Die Programmstruktur wurde durch die Übersetzung verändert! Kritik – Zusammenfassung ▶ Übersetzung von Pattern Matching-Ausdrücken ist alles andere als trivial ▶ Wenn sich nicht alle Ausdrücke nach ihrer Branch Clock richten kann nicht 1:1 übersetzt werden ▶ Automatisches Umschreiben ist möglich, kann aber u.U. keine Abhängigkeiten bewahren ▶ Theoretische Überlegungen somit praktisch nicht umsetzbar Verwandte Arbeiten Verwandte Arbeiten ▶ ARGOS: Beschreibung reaktiver Systeme als Automaten mittels graphischer Syntax ▶ SYNCHRONIE: Integration imperativer, deklarativer und graphischer Programmierparadigmen ▶ Girault et al.: Semantik hierarchische endliche Zustandsautomaten ▶ Mode-Automata: Erweiterung von LUSTRE um Automaten als Kontrollstruktur ▶ Pouzet et al.: Clock Calculus als Typsystem angelehnt an ML Adaptionen LUCID SYNCHRONE Compiler: ▶ Implizite Filterung von freien Variablen ▶ Unterausdrücke nie schneller als Branch Clock SCADE Compiler (experimentell): ▶ Beschränkt auf Aufzählungstypen (keine Argumente in Konstruktoren) ▶ Pattern Matching als mehrere Kontrollstrukturen in Hostsprache kompiliert ▶ Genutzt zur Modellierung von Automaten Fazit Fazit ▶ Ausführliche Ausarbeitung zu varianten Typen und Pattern Matching als Kontrollstruktur auf theoretischer Ebene ▶ Erfolgreiche Umsetzung des Clock Calculus als Kontrollstruktur ▶ Übertragung von der Theorie in die Praxis herausfordernd Diskussion Fragen?