Ziele
- foundation
- collection framework, via arrays
- query sprache
- brauchen wir objectIds, wenn wir nur immutalbe objects haben
- computational approach: inbuilt things are cheap, not like a semantic equal on functions!
- problem with datastructures: array (Prolog, StandardML Lists) can be simulated by functions, but costs are different! costs depend on mutable objects are different for single update or array copy ⇒ what is functional cost?
- semantische db, sql Mängel
- Namen für Joins mit leichter wiederverwendbarkeit
- Datentypen im LegoSystem (z.B. Tupel überall wo ein atomic value erlaubt ist, Operationen auf allen TupelElementen mit bestimmten Datentype, NamensPattern usw..), Metadaten Operationen
- ddl, constraint language ⇒ immutable objects
- eigentlich möchten wir ein Array Syntax entwickeln, aber mit Rekursion können wir alles machen! Wir bräuchten also (fast) ebenso mächtige Alternative anstelle der Rekursion!
- Problems
- Rekursion über list enthält implizit Reihenfolge - das ist aber meist überspezifiziert!
- pick random function
- pick random und reduce/combine wie in java streams
- oder split: sum = fun(a) if size(a) = 0 then 0 elif size(a) = 1 then a[0] else b = split(a); sum(b[0]) + sum(b[1]); endFun
- aber rekursion ist einfacher: sum = fun(a) if size(a) = 0 then 0 else a[0] + sum(a[1..]); endFun
- oder funktional sum = fun(a) iterate(0, e → e[0], +)
- where = fun(f) = iterate([], e → if f(e) then [e] else [] endIf endFun, &)
- eigentlich gilt da auch schon für Array, meist brauchen wir container ohne Reihenfolge
- update of singel element ==> fun(a, i, e) sub(a, 0, i) & [e] & sub(a,i+1, size(a)) endFun ist einfach, aber vielleicht brauchen wir das als elementarOperation?
- Rekursion über list enthält implizit Reihenfolge - das ist aber meist überspezifiziert!
Syntax
- U = Universe of base type values including (disjoint)
- Bool = {true, false}
- Integer
- V = Values: U plus tuples and functions: disjoint Union (of minimal closure)
- U
- Arr = Arrays = V*
- Fun = Functions
- Arr: a ∈ Arr ⇔
- size(a) ∈ Nat,
- a[i] ∈ U for i ∈ [0, size(a)-1]
- [u0, u1, ... un-1] ∈ Arr with [..., ui, ... ][i] = ui
- concat
- sub(a, b, e) = subarray von [a[b], ..., a[e-1]]
- Fun defined by the following recursive syntax for fun
- fun = fun(newVar*) e endFun
- p = u | var | ( e ) | p( e* ) | p? [ e* ] | if e then e else e endIf | fun
- u = constant from U
- e = p | op e | e op | e op e | forward newVar+ | newVar = e | e ; e
- op = operands including
- usual operands for Bool and Int
- & for array concatenation
- lifting operators to arrays mittels syntax oder explizite Funktionen? a = b ⇒ fun(a,b) if size(a) <> size(b) then false elif size(a) = 0 then true else a[0] = b[0] and eq(sub(a, 1), sub(b,1)) endIf
- firstNE = fun(a, b, op, ee, aLo, bLo) laEq = fun(i) if i >= size(a) or i >= size(b) then i-1 elif a[i] <> b[i] then i-1 else laEq(i+1) endFun; l = laEq(0); if l >= size(a) then if l >= size(b) then ee else aLo endIf else if l>=size(b) then bLo else op(a[l], b[l]) endIf
- predefined functions
- size: Arr → Nat
- sub: Arr × Nat × Nat → Arr: subarray
- isBase, isArray, isFun: U → Bool
- operators can bee used as functions, if syntax allows both, operator is preferred -- how implement overloaded operators on base types?
- args: Fun → Nat number of arguments
variables
- variable are immutable, instanciated by assignment or function call
- variables nested by function scope, including formal parameters
- variable scope: procedure nested (algol like)
- forward: use only after definition (function call, not definition, d.h. rekursiv alle forwards aufgelöst - ist x=fun spezialfall oder nicht?)
List
List: null oder
- ele: List → V
- next: List → List
- List: U × List → List: Constructor
- terminating condition
- array2list = fun(a) if a.size = 0 then List[] else List[a[0], array2list(sub(a, 1))] endIf
ListAlgebra
Operators on List:
- l is an expression yielding a list
- f is an expression used as a function with implicit arguments argument l: List
- l where f:
fun(lst, f) if args(f) = 1 then w1 = fun(l) if l = null then null elif f(l.ele) then List(l.ele, w1(l.next)) else w1(l.next) endIf endFun; w1(lst); else w2 = fun(l, a) if l = null then null else r = f(l.ele, a); if r[0] then List(l.ele, w2(l.next, r)) else w2(l.next, r) endIf endIf endFun; w2(lst, null); endIf
- l map f: transform each element
- l order f: sort
- l flat
- l group f: (a group f flat ms) = (a ms) ...
- l ms: MultiSet tuples [ele, count]
- l set
Beispiel
- row_numer() over(partition by p order by o) =
fun(lst, p, o) lst group p map (l order o map if a = null then [[0] & l.ele, 0] else [[a[1]+1] & l.ele, [a1]+1] endif) flat
named tuples
- named tuples: a 'as' '[' newVar (',' newVar)* ']'
- Suche 1) Variables 2) named Elements (erstes oder eindeutig?)
- für where usw.: sind fuctions, aber mit implizit parameter von letztem from (oder group by usw.) -- aber braucht 2 Namen, einen für collection, einen für ele, z.B. mit query oder Apostroph, oder Operator ArrayItBelongsTo
Syntax Erweiterung
- p = .... | p '.' nat | p '.' name | p'[' (string or nat)+ ']'
ddl / constraints
- equal immer deep equal, object Identifier of Array is irrelevant!
- isSubArray(s, a) ⇔ ∃ p: s = a where p
- isSubMulti(s, a) ⇔ ∃ p, o: s = a where p order o
- isSubSet(s, a) ⇔ ∃ p: s 2set = a where p 2set
- orthogonales Konzept von entity- baseValued und single- multiValued attributes