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?