Created
June 29, 2016 18:27
-
-
Save m1dnight/8f3b8c34a1f5a718bd3ff854c41ebe59 to your computer and use it in GitHub Desktop.
Session Typed Lambda Calculus (Vasconcelos 2006)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main where | |
import Control.Arrow | |
import Debug.Trace | |
import Control.Monad.State | |
import Data.List hiding (union) | |
import Data.Maybe | |
import Syntax | |
import Text.Printf | |
-- ____ _ _____ _ | |
-- / ___| ___ ___ ___(_) ___ _ __ |_ _| _ _ __ ___ __| | | |
-- \___ \ / _ \/ __/ __| |/ _ \| '_ \ | || | | | '_ \ / _ \/ _` | | |
-- ___) | __/\__ \__ \ | (_) | | | | | || |_| | |_) | __/ (_| | | |
-- |____/ \___||___/___/_|\___/|_| |_| |_| \__, | .__/ \___|\__,_| | |
-- |___/|_| | |
-- | | __ _ _ __ ___ | |__ __| | __ _ / ___|__ _| | ___ _ _| |_ _ ___ | |
-- | | / _` | '_ ` _ \| '_ \ / _` |/ _` | | | / _` | |/ __| | | | | | | / __| | |
-- | |__| (_| | | | | | | |_) | (_| | (_| | | |__| (_| | | (__| |_| | | |_| \__ \ | |
-- |_____\__,_|_| |_| |_|_.__/ \__,_|\__,_| \____\__,_|_|\___|\__,_|_|\__,_|___/ | |
-- | |
-- Based on the work by Vasconcelos et al. | |
-- Vasconcelos, V. T., Gay, S. J., & Ravara, A. (2006). Type checking | |
-- a multithreaded functional language with session types. Theoretical | |
-- Computer Science. http://doi.org/10.1016/j.tcs.2006.06.028 | |
----------- | |
-- Notes -- | |
----------- | |
-- 1) One thing I did not notice at first was that all the expression | |
-- are in A-normal form: | |
-- https://en.wikipedia.org/wiki/A-normal_form. This makes the | |
-- typechecker a lot easier because you can make assumptions about | |
-- the actual result of typing an expression, namely that they are | |
-- all values. | |
-------------------------------------------------------------------------------- | |
--- HELPERS -------------------------------------------------------------------- | |
-------------------------------------------------------------------------------- | |
-- Extend environment. | |
extend env v t = case lookup v env of | |
Just t -> error $ printf "Shadowing binding of variable: %s to %s, in %s" (show v) (show t) (show env) | |
Nothing -> (v,t):env | |
-- Union two environments (pointwise extend). | |
union = foldr (\e acc -> (uncurry $ extend acc) e) | |
-- Extract a binding from the environment. | |
-- Assumes that there are only unique keys in the environment! | |
extract key env = case partition (\(k,v) -> k == key) env of | |
([(_,v)], rest) -> (v, rest) | |
_ -> error "key not found" | |
-- Pointwise extraction | |
extractset env env' = foldr (\(k,v) acc -> snd $ extract k acc) env' env | |
-- Generate fresh variable name. | |
--fresh = AId "freshid" | |
fresh = do i <- get | |
put (1 + i) | |
return $ AId (show i) | |
-- Check if a label exists in a given in/external choice. | |
validLabel cs lbl = isJust $ lookup lbl cs | |
-- All elements of the list equal to eachother? | |
allsame [] = True | |
allsame xs = all (head xs ==) (tail xs) | |
-- Dual of a session type. | |
dual (SReceiveD d s) = SSendD d (dual s) | |
dual (SSendD d s) = SReceiveD d (dual s) | |
dual (SReceiveS s s') = SSendS s' (dual s) | |
dual (SSendS s s') = SSendS s' (dual s) | |
dual (SExternal lss) = SInternal $ map (second dual) lss | |
dual (SInternal lss) = SExternal $ map (second dual) lss | |
dual SEnd = SEnd | |
-------------------------------------------------------------------------------- | |
--- TYPECHECKER ---------------------------------------------------------------- | |
-------------------------------------------------------------------------------- | |
-- The state is just an integer. | |
type St = Integer | |
------------ | |
-- Values -- | |
------------ | |
typeVal :: [(String, S)] -> [(String, Typ)] -> V -> State St ([(String, S)], Typ, [(String, S)]) | |
-- C-Const | |
-- Γ ; unit ↦ Unit | |
typeVal sigma gamma VUnit = return (sigma, TD DUnit, []) | |
typeVal sigma gamma (VNum i) = return (sigma, TD DNum, []) | |
-- C-Chan | |
-- Γ ; γᵖ ↦ Chan γᵖ | |
typeVal sigma gamma (VAlpha chanid) = return (sigma, Chan chanid, []) | |
-- C-Var | |
-- Γ,x:T ; x ↦ T | |
typeVal sigma gamma (VVar var) = let mvarT = lookup var gamma | |
in | |
return (sigma, fromMaybe (error $ printf "Variable %s unbound" var) mvarT, []) | |
-- C-Abs | |
-- Γ,x:T ; Σ; e ↦ Σ₁;U;Σ₂ | |
-- ----------------------------------- | |
-- Γ ; λ(Σ;x:T).e ↦ (Σ;T → U;Σ₁,Σ₂) | |
typeVal sigma gamma (VLambda σ x t e) = do let gamma' = (x,t):gamma | |
(σ1, u, σ2) <- typeExp sigma gamma' e | |
return (sigma, TD $ DArrow σ t u (σ1 `union` σ2), []) | |
-- C-Rec | |
-- Γ,x:T ; v ↦ T T = (Σ;U → U';Σ') | |
-- ---------------------------------- | |
-- Γ ; rec(x:T).v ↦ T | |
typeVal sigma gamma (VRec x t v) = let gamma' = extend gamma x t | |
in | |
do (_, typ, _) <- typeVal sigma gamma' v | |
return (sigma, typ, []) | |
----------------- | |
-- Expressions -- | |
----------------- | |
typeExp :: [(String, S)] -> [(String, Typ)] -> E -> State St ([(String, S)], Typ, [(String, S)]) | |
-- C-ReceiveD | |
-- Γ ; v ↦ Chan α | |
-- -------------------------------------- | |
-- Γ ; Σ,α:?D.S ; receive v ↦ Σ ; D ; α:S | |
-- C-ReceiveS | |
-- Γ ; v ↦ Chan α c fresh | |
-- ------------------------------------------------- | |
-- Γ; Σ,α:?S'.S ; receive v ↦ Σ ; Chan c ; c:S', α;S | |
typeExp sigma gamma (EReceive v) = do (_,Chan α,_) <- typeVal sigma gamma v | |
let (st, σ) = extract (cid α) sigma | |
case st of | |
(SReceiveD d s) -> return (σ, TD d, [(cid α, s)]) | |
(SReceiveS s' s) -> do c <- fresh | |
return (σ, Chan c, [(cid c, s'), (cid α, s)]) | |
-- C-SendD | |
-- Γ ; v' ↦ Chan α Γ ; v ↦ D | |
------------------------------------------------------- | |
-- Γ ; Σ, α:!D.S ; send v on v' ↦ Σ ; Unit ; α:S | |
-- C-SendS | |
-- Γ ; v' ↦ Chan α Γ ; v ↦ Chan β | |
------------------------------------------------------- | |
-- Γ ; Σ, α:!S'.S, β:S' ; send v on v' ↦ Σ ; Unit ; α:S | |
typeExp sigma gamma (ESend v v') = do (_,Chan α,_) <- typeVal sigma gamma v' | |
(_,vT,_) <- typeVal sigma gamma v | |
let (stα, σ) = extract (cid α) sigma | |
case stα of | |
(SSendD d s) -> if TD d /= vT | |
then error "Types for session do not match sent value." | |
else return (σ, TD DUnit, [(cid α, s)]) | |
(SSendS s' s) -> let (Chan β) = vT | |
(stβ, σ') = extract (cid β) σ | |
in | |
if s' /= stβ | |
then error "Session types do not match for sending channel" | |
else return (σ', TD DUnit, [(cid α, s)]) | |
-- C-Select | |
-- Γ ; v ↦ Chan α j ∈ I | |
----------------------------------------------------------- | |
-- Γ ; Σ, α:⊕⟨lᵢ : Sᵢ⟩ ; select lⱼ on v ↦ Σ ; Unit ; α : Sⱼ | |
typeExp sigma gamma (ESelect l v) = do (_,Chan α,_) <- typeVal sigma gamma v | |
let (stα, σ) = extract (cid α) sigma | |
case stα of | |
(SExternal cs) -> if validLabel cs l | |
then let si = fromMaybe (error "Oops?") $ lookup l cs | |
in | |
return (σ, TD DUnit, [(cid α, si)]) | |
else error "Invalid label selected." | |
-- C-Case | |
-- Γ ; v ↦ Chan α ∀ j ∈ I.(Γ ; Σ,α:Sⱼ ; eⱼ ↦ Σ₁ ; T ; Σ₂) | |
------------------------------------------------------------ | |
-- Γ ; Σ,α:&⟨lᵢ : Sᵢ⟩ ; case v of {lᵢ ⇒ eᵢ} ↦ Σ₁ ; T ; Σ₂ | |
typeExp sigma gamma (ECase v les) = do (_,Chan α,_) <- typeVal sigma gamma v | |
let (stα, σ) = extract (cid α) sigma | |
case stα of | |
(SInternal cs) -> do casetypes <- mapM typeCase les | |
if allsame casetypes | |
then return $ head casetypes | |
else error "Not all cases have the same type" | |
where typeCase (lj,ej) = if validLabel cs lj | |
then let sj = fromMaybe (error "") $ lookup lj cs | |
in | |
typeExp sigma gamma ej | |
else error "Invalid label in case" | |
-- C-Close | |
-- Γ ; v ↦ Chan α | |
--------------------------------------- | |
-- Γ ; Σ,α:End ; close v ↦ Σ ; Unit ; ∅ | |
typeExp sigma gamma (EClose v) = do (_,Chan α,_) <- typeVal sigma gamma v | |
let (stα, σ) = extract (cid α) sigma | |
case stα of | |
SEnd -> return (σ, TD DUnit, []) | |
-- C-Accept | |
-- Γ ; v ↦ [S] c fresh | |
-------------------------------------- | |
-- Γ ; Σ ; accept v ↦ Σ ; Chan c ; c:S | |
typeExp sigma gamma (EAccept v) = do (_,TD (DSession s),_) <- typeVal sigma gamma v | |
c <- fresh | |
return (sigma, Chan c, [(cid c, s)]) | |
-- C-Request | |
-- Γ ; v ↦ [S] c fresh | |
--------------------------------------------- | |
-- Γ ; Σ ; accept v ↦ Σ ; Chan c ; c:(dual S) | |
typeExp sigma gamma (ERequest v) = do (_,TD (DSession s),_) <- typeVal sigma gamma v | |
c <- trace (printf "SIG: %s :SIG" (show sigma)) $ fresh | |
return (sigma, Chan c, [(cid c, dual s)]) | |
-- C-App | |
-- Γ ; v ↦ (Σ ; T ↦ U ; Σ') Γ ; v' ↦ T | |
----------------------------------------- | |
-- Γ ; Σ,Σ" ; v v' ↦ Σ" ; U ; Σ' | |
typeExp sigma gamma (EApp v v') = do (_, TD (DArrow σ t u σ'),_) <- typeVal sigma gamma v | |
(_,t',_) <- typeVal sigma gamma v' | |
let σ'' = extractset σ sigma | |
if t /= t' | |
then error $ printf "Types for application do not match: %s and %s" (show t) (show t') | |
else return (σ'', u, σ') | |
-- C-New | |
-- Γ ; Σ ; new S ↦ Σ ; [S] ; ∅ | |
typeExp sigma gamma (ENew s) = return (sigma, TD (DSession s), []) | |
typeExp sigma gamma (ET t) = typeThread sigma gamma t | |
-- C-Let | |
-- Γ ; Σ ; e ↦ Σ₁ ; T₁ ; Σ₁' Γ,x:T₁ ; Σ₁,Σ₁' ; t ↦ Σ₂ ; T₂ ; Σ₂' | |
------------------------------------------------------------------- | |
-- Γ ; Σ ; let x = e in t ↦ Σ₁ ∩ Σ₂ ; T₂ ; (Σ₁' ∩ Σ₂),Σ'₂ | |
typeThread :: Sigma -> Gamma -> T -> State St (Sigma, Typ, Sigma) | |
typeThread sigma gamma (TLet x e t) = do (σ1, t1, σ1') <- typeExp sigma gamma e | |
let gamma' = extend gamma x t1 | |
sigma' = union σ1 σ1' | |
(σ2, t2, σ2') <- typeThread sigma' gamma' t | |
return (σ1 `intersect` σ2, t2, (σ1' `intersect` σ2) `union` σ2') | |
-- C-Fork | |
-- Γ ; Σ ; t ↦ Σ₁ ; T₁ ; ∅ Γ ; Σ₁ ; t' ↦ Σ₂ ; T₂ ; ∅ | |
-------------------------------------------------------- | |
-- Γ ; Σ ; (fork t ; t') ↦ Σ₂ ; T₂ ; ∅ | |
typeThread sigma gamma (TFork t t') = do (σ1, t1,_) <- typeThread sigma gamma t | |
(σ2, t2,_) <- typeThread σ1 gamma t' | |
return (σ2, t2, []) | |
-- C-Val | |
-- Γ ; v ↦ T | |
------------------------ | |
-- Γ ; Σ ; v ↦ Σ ; T ; ∅ | |
typeThread sigma gamma (TV v) = typeVal sigma gamma v | |
-------------------------------------------------------------------------------- | |
--- TEST INPUTS ---------------------------------------------------------------- | |
-------------------------------------------------------------------------------- | |
------------- | |
-- Threads -- | |
------------- | |
-- let x = new End in x | |
t01 = TLet "x" (ENew SEnd) | |
(TV (VVar "x")) | |
-- let x = (λx:Int . x) 5 in x | |
t02 = TLet | |
"x" | |
(EApp (VLambda [] "y" (TD DNum) (ET (TV (VVar "y")))) | |
(VNum 5)) | |
(TV (VVar "x")) | |
-- fork (let x = new !Int.?Int.End in (accept x)); | |
-- (let y = new !Int.?Int.End in (request x)) | |
t03 = TFork | |
(TLet | |
"s" | |
(ENew (SSendD DNum (SReceiveD DNum SEnd))) | |
(TLet | |
"x" | |
(EAccept (VVar "s")) | |
(TV (VVar "x")))) | |
(TLet | |
"t" | |
(ENew (SSendD DNum (SReceiveD DNum SEnd))) | |
(TLet | |
"y" | |
(ERequest (VVar "t")) | |
(TV (VVar "y")))) | |
ts = [t01, t02, t03] | |
----------------- | |
-- Expressions -- | |
----------------- | |
-- (rec (x:Num).(λ(∅;y:Num) y)) 5 | |
e01 = EApp v02 (VNum 5) | |
es = [e01] | |
------------ | |
-- Values -- | |
------------ | |
-- λ(∅;y:Num) y | |
v01 = VLambda [] "y" (TD DNum) (ET (TV (VVar "y"))) | |
-- rec (x:Num).(λ(∅;y:Num) y) | |
v02 = VRec "x" (TD DNum) v01 | |
vs = [v01, v02] | |
-------------------------------------------------------------------------------- | |
--- MAIN ----------------------------------------------------------------------- | |
-------------------------------------------------------------------------------- | |
main = do print "Threads" | |
mapM_ (\e -> print $ evalState (typeThread [] [] e) 1) ts | |
print "Expressions" | |
mapM_ (\e -> print $ evalState (typeExp [] [] e) 1) es | |
print "Values" | |
mapM_ (\e -> print $ evalState (typeVal [] [] e) 1) vs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Syntax where | |
-- _ ____ _____ | |
-- / \ / ___|_ _| | |
-- / _ \ \___ \ | | | |
-- / ___ \ ___) || | | |
-- /_/ \_\____/ |_| | |
data T | |
= TV V | |
| TLet String E T | |
| TFork T T | |
deriving (Show, Eq) | |
data E | |
= ET T | |
| EApp V V | |
| ENew S | |
| EAccept V | |
| ERequest V | |
| ESend V V | |
| EReceive V | |
| ECase V [(L, E)] | |
| ESelect L V | |
| EClose V | |
deriving (Show, Eq) | |
data V | |
= VAlpha Alpha | |
| VLambda Sigma String Typ E | |
| VRec String Typ V | |
| VUnit | |
| VVar String | |
| VNum Integer | |
deriving (Show, Eq) | |
-- _____ | |
-- |_ _| _ _ __ ___ ___ | |
-- | || | | | '_ \ / _ \/ __| | |
-- | || |_| | |_) | __/\__ \ | |
-- |_| \__, | .__/ \___||___/ | |
-- |___/|_| | |
data Alpha | |
= AId { cid :: String } | |
| EId P | |
deriving (Show, Eq) | |
data P | |
= Plus | |
| Minus | |
deriving (Show, Eq) | |
data Typ | |
= TD D | |
| Chan Alpha | |
deriving (Show, Eq) | |
data D | |
= DSession S | |
| DArrow Sigma Typ Typ Sigma | |
| DUnit | |
| DNum | |
deriving (Show, Eq) | |
data S | |
= SReceiveD D S | |
| SSendD D S | |
| SReceiveS S S | |
| SSendS S S | |
| SExternal [(L, S)] | |
| SInternal [(L, S)] | |
| SEnd | |
deriving (Show, Eq) | |
type Sigma = [(String, S)] | |
type Gamma = [(String, Typ)] | |
type L = String |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment