+-----+ +-----+
input | | intermediate | | output
------>| F |-------------->| G |------->
data | | data | | data
+-----+ +-----+
+----------+
input | | output
------>| FG |------->
data | | data
+----------+
In case of emergency, you can:
F a better producerG a better consumerTerms are used for meta-programming and as data.Processes are used to describe behavior.Types enforce a safe use of data by terms.Sessions enforce a safe behavior of processes.Dependent types and sessions enable formal verification.Duality sessions enables fusion.\[(A·B)_{ij} = \sum_{k=0}^{m-1} A_{ik} × B_{kj}\]
Bₘₓₚ
Aₙₓₘ
(A·B)ₙₓₚ
| \(zipP(u,v)_k\) | \(= u_k × v_k\) |
| \(sumD(w)\) | \(= \sum_{k=0}^{m-1} w_{k}\) |
| \(dotP(u,v)\) | \(= sumD(zipP(u,v))\) |
Notations
? : What I am going to read?
! : Here is what I write!
double =
proc{a: ?Int, b: !Int}
let x <- a.
b <- x + xproc{b: !Int}
new (a: Int).
a <- 21.
@double{a, b} Replacing @double by its definition:
proc{b: !Int}
new (a: Int).
a <- 21.
let x <- a.
b <- x + xFusing away the allocation:
proc{b: !Int}
let x = 21.
b <- x + xExpanding local definitions:
proc{b: !Int}
b <- 42Think again...
A type is an approximation
which enables abstraction
+--------+
a | | d = a / b
--->| |----------->
| divmod |
--->| |----------->
b | | m = a % b
+--------+
proc{ a: ?Int, b: ?Int , d: !Int, m: !Int } -- Any order
proc[: a: ?Int, b: ?Int , d: !Int, m: !Int :] -- In order
proc[ a: ?Int, b: ?Int , d: !Int, m: !Int ] -- All in parallel
proc[: [a: ?Int, b: ?Int], [d: !Int, m: !Int] :] -- ∥ read; ∥ write
proc[: {a: ?Int, b: ?Int}, [d: !Int, m: !Int] :] -- Any read; ∥ write
let x <- a.
let y <- b.
d <- x / y.
m <- x % y
( let x <- a
| let y <- b).
( d <- x / y
| m <- x % y)
let y <- b.
let x <- a.
m <- x % y.
d <- x / y
let x <- a.
let y <- b.
( d <- x / y
| m <- x % y)
let y <- b.
let x <- a.
( d <- x / y
| m <- x % y)
( let x <- a
| let y <- b).
d <- x / y.
m <- x % y
| S | ~S |
|---|---|
!A |
?A |
{S₀, ..., Sₙ} |
[~S₀, ..., ~Sₙ] |
[:S₀, ..., Sₙ:] |
[:~S₀, ..., ~Sₙ:] |
Example
~{ !Int, [: ?Double, ?Int:]}
= [~!Int,~[: ?Double, ?Int:]]
= [ ?Int,~[: ?Double, ?Int:]]
= [ ?Int, [:~?Double,~?Int:]]
= [ ?Int, [: !Double, !Int:]]
S a session (!Int, {!Int,?Double})F a process following SG a process following the dual of Snew [ c : S, d : ~S ].
( @F{c}
| @G{d} )new [: c : S, d : ~S :].
@F{c}.
@G{d}F = proc(u: {!Int^100}) ...
G = proc(u: {?Int^100}) ...
FG = proc()
new/alloc [: u: {!Int^100}, v: {?Int^100} :]
@F{u}.
@G{v}Or:
F = proc(u: [!Int^100]) ...G = proc(u: [?Int^100]) ...zipP = zipWith Double Double Double _*D_zipWith =
\(A B C: Type)
(f: (a: A)(b: B)-> C)
(n: Int)->
proc{[: a: ?A^n :], [: b: ?B^n :], [: c: !C^n :]}
slice (a,b,c)^n (cc <- f (<- a) (<- b))sumD = foldl Double Double _+D_ 0.0foldl = \(A B: Type)
(f: (acc: B)(a: A)-> B)
(init: B)
(n: Int)->
proc[: [: ai: ?A^n :], cr: !B :]
new (tmp: B).
tmp <- init.
slice (ai)^n
(tmp <- f (<- tmp) (<- a)).
fwd(?B)(tmp,cr)dotP = \(n : Int)->
proc{u: [: ?Double^n :],
v: [: ?Double^n :],
o: !Double}
new [: w: [: !Double^n :], w' :]
@(zipP n){u, v, w}.
@(sumD n)[:w', o:]fused_dotP = \(n : Int)->
proc{[: ai: ?Double^n :],
[: bi: ?Double^n :],
o : !Double}
new (tmp : Double).
tmp <- 0.0.
(slice (ai, bi)^n
let a <- ai.
let b <- bi.
let c <- tmp.
tmp <- (c +D (a *D b))).
let x <- tmp.
o <- x| Precision | + Modularity |
| = |
Cost Free Abstraction!
Fusion:
predictable + safe + automatic