Notes (Week 10 Tuesday)
Table of Contents
These are the notes I presented and added to in today's lecture. -Rob
1. Notes
Scheduler ========= If we don't know anything about a scheduler, we assume it can choose whatever interleavings between processes it wants, for example: x-x-x-x-x-x-x-x y-y-y-y-y-y-y-y x-x-x- x-x-x y-y- x- x- x- x- y- y- y- y etc. Session Types ============= Choice and selection -------------------- // Server process: providing *choice* serve_eat_here |- Δ, x : SEatHere serve_takeaway |- Δ, x : STakeAway ------------------------------------------------------------------ & x.case(serve_eat_here,serve_takeaway) |- Δ, x : SEatHere & STakeAway SEatHere = dual(EatHere) STakeAway = dual(TakeAway) SEatHere & STakeAway = dual(EatHere (+) TakeAway) // Customer process: making *selection* // Selection 1: send choice "eat here" then wait for food eat_here |- Γ, x : EatHere ---------------------------------------------- (+)1 x[inl].eat_here |- Γ, x : EatHere (+) TakeAway EatHere = dual(SEatHere) TakeAway = dual(STakeAway) EatHere (+) TakeAway = dual(SEatHere & STakeAway) // Selection 2: send choice "takeaway" then wait for takeaway takeaway |- Γ, x : TakeAway ---------------------------------------------- (+)2 x[inr].takeaway |- Γ, x : EatHere (+) TakeAway // Dynamic Semantics of Choice/Selection Run 1: left choice ch x. x[inl].eat_here | x.case(serve_eat_here,serve_takeaway) ==> ch x. (eat_here | serve_eat_here) Run 2: right choice ch x. [inr].takeaway | x.case(serve_eat_here,serve_takeaway) ==> ch x. (takeaway | serve_takeaway) Input and output (incl. empty input/output) ------------------------------------------- // Customer process x[y].(pay | x(z).x().get_receipt) // Customer process typing derivation get_receipt |- y:GetReceipt ----------------------------------- ⊥ x().get_receipt |- y:GetReceipt,x:⊥ ----------------------------------------- ⅋ pay |- y : Pay x(z).x().get_receipt |- x: GetReceipt ⅋ ⊥ --------------------------------------------------------------- (x) x[y].(pay | x(z).x().get_receipt) |- x: Pay (x) (GetReceipt ⅋ ⊥) // Server process x(y).x[z].(give_receipt | x[].0) // Server process typing derivation Having derived the customer process type, we figured out what the server process' type ought to be by taking its dual: dual (GetReceipt ⅋ ⊥) = dual(GetReceipt) (x) 1 x(y).x[z].(give_receipt | x[].0) |- x: dual(Pay) ⅋ (dual(getReceipt) (x) 1) But constructing the typing derivation tree makes sure of it: ------------ 1 give_receipt |- y:dual(Pay),z:GiveReceipt x[].0 |- x:1 --------------------------------------------------------------- (x) x[z].(give_receipt | x[].0) |- y:dual(Pay), x:(GiveReceipt (x) 1) ------------------------------------------------------------------- ⅋ x(y).x[z].(give_receipt | x[].0) |- dual(Pay) ⅋ (GiveReceipt (x) 1) // Dynamic Semantics of Input/Output // Relevant reduction/equivalence rules ch x. (x[y].(P | Q) | x(y).R) ==> ch y. (P | ch x. (Q | R)) "beta-(x)⅋" ch x. (x[].0 | x().P) ==> P "beta-1⊥" ch x:A. (P | Q) == ch x:dual(A).(Q | P) "swap" Customer Server ch x. (x[y].(pay | x(z).x().get_receipt) | x(y).x[z].(give_receipt | x[].0)) ==> "beta-(x)⅋" ch y. (pay | ch x. (x(z).x().get_receipt | x[z].(give_receipt | x[].0))) ==> "swap" ch y. (pay | ch x. (x[z].(give_receipt | x[].0)) | x(z).x().get_receipt) ==> "beta-(x)⅋" ch y. (pay | ch z. (give_receipt | ch x. (x[].0 | x().get_receipt))) ==> "beta-1⊥" ch y. (pay | ch z. (give_receipt | get_receipt)) Deadlock freedom of Session Types --------------------------------- P |- Γ, x : A Q |- Δ, x : dual(A) -------------------------------------- Cut ch x:A. (P | Q) |- Γ, Δ - Absence of communication loops between P and Q. - Wadler: "Communications along Γ and Δ are disjoint, so P and Q are restricted to communicate with each other only along x. If communication could occur along two channels rather than one, then one could form a loop of communications between P and Q that leads to deadlock." - Examples of deadlock-prone concurrent processes: ch x. (x(u).wait_meal | x(v).wait_payment) - won't type check, because their types for x aren't dual ch x, y. (x(u).wait_meal | y(v).wait_payment) - also won't type check, because we can't introduce ch for two channels at once - These would be rejected by session types, because Cut is the only typing rule to introduce a `ch` binder when typechecking parallel composition of two well-typed processes, and (1) their types for the one channel must be dual, and (2) Cut does not allow you to bind more than one channel simultaneously for these processes to communicate by: ---------------------------------------------------------------- Cut? no. ch x:A⅋C. ch y:B⅋D. (x(u).wait_meal | y(v).wait_payment) |- Γ, Δ What if you *wanted* to express systems that allow deadlock? ------------------------------------------------------------ - An additional rule "Binary Cut allows one to express systems where communications form a loop and may deadlock" P |- Γ, x : A, y : B Q |- Δ, x : dual(A), y : dual(B) ---------------------------------------------------------- BiCut ch x:A, y:B. (P | Q) |- Γ, Δ - The deadlock-prone example would be accepted by session types with BiCut R |- Θ, y : A, x : B ---------------------- ⅋ x(y).R |- Θ, x : A ⅋ B (NB: Remember, order in session typing environments is ignored) etc. etc. ---------------------------- --------------------------------------------- wait_meal |- Γ,u:A,x:C,y:B⅋D wait_pay |- Δ,x:dual(A⅋C),v:dual(B),y:dual(D) ---------------------------- --------------------------------------------- x(u).wait_meal |- Γ,x:A⅋C,y:B⅋D y(v).wait_pay |- Δ,x:dual(A⅋C),y:dual(B⅋D) --------------------------------------------------------------------------- ch x:A⅋C,y:B⅋D. (x(u).wait_meal | y(v).wait_pay) |- Γ, Δ Final Exam ========== - Online with a login (we'll give you credentials) - 2 hours within a 4 hour window (last year) - Open book, but no active seeking of answers (via online interactions etc)