The modified rule:
[a. B] is c-ordinary
B is not c-ordinary <==> B1 <| B |> B2
==> B is s-ordinary
==> a in FvNeg(B)
A' is part of the mu-domains of A
if a in FvNeg(A')
then dropLabel(a, A') <: dropLabel(a, B)
and dropLabel(a, B) <: dropLabel(a, A')
else A' <: B
-----------------------------
A <: [a. B]
mu a. A & mu a. B <: mu a . A & B
A <: B <: C
B1 <| B |> B2
B <: C
---------
either B1 <: C or B2 <: C
Why isomorphic check?
We want to avoid the non-derivable:
mu b. mu a. a -> Int
& mu b. mu a. b -> Bool
<:
mu b. mu a. (a -> Int) & (b -> Bool)
translates to:
[b. [a. {a : a -> Int} -> Int]]
& [b. [a. {b : [a. b -> Bool] } -> Bool]]
<:
[b. [a.
( {a : (a -> Int) & (b -> Bool) } -> Int )
&. ( {b : [a. ( .... ) & (b -> Bool) ]} -> Bool )
]]
after dropping label `b`
[b. [a. {a : a -> Int} -> Int]]
& [b. [a. b -> Bool]]
<:
[b. [a.
( {a : (a -> Int) & (b -> Bool) } -> Int )
&. ( b -> Bool )
]]
the subtyping is still not isomorphic
Why part of relation?
To ensure fields can be dropped, discussed last week
Why dropLabel function
This is to ensure one-layer merge is still allowed, consider the simplest:
mu a. a -> (mu b. b -> (Int & Bool))
& mu a. a -> Bool
<:
mu a. (a -> (mu b. b -> (Int & Bool))) & (a -> Bool)
[a. {a : a -> [b. ... ]} -> [b. ... ] ]
& [a. {a : a -> Bool} -> Bool]
<:
[a. {a : (a -> [b. ... ]) & (a -> Bool) } -> [b. ... ]
& {a : (a -> [b. ... ]) & (a -> Bool) } -> Bool ]
The right type will be split first
SubGoal (1)
[a. {a : a -> [b. ... ]} -> [b. ... ]]
& [a. {a : a -> Bool} -> Bool]
<:
[a. {a : (a -> [b. ... ]) & (a -> Bool) } -> [b. ... & ... ]
Even after relaxed with the `partof` relation
[a. {a : a -> [b. ... ]} -> [b. ... ]]
<:[a. {a : (a -> [b. ... ]) & (a -> Bool) } -> [b. ... ]]
Still we have negative variables, so the two types are not iso-morphic unless label a are dropped: [a. a -> Int ] ~ [a. a -> Int]
Note: the part relation must be exhaustive
parts :: STyp -> [STyp]
parts (SAnd a b) = parts a ++ parts b
parts (TMu a) = [TMu a]
parts (SFun a b) = [SFun a b' | b' <- parts b]
parts (SRcd l a) = [SRcd l a' | a' <- parts a]
parts t = [t]
-- [mcodPos k t] collect all the (positive) intersection components of t
mcodPos :: Int -> STyp -> [STyp]
mcodPos k (SAnd a b) = mcodPos k a ++ mcodPos k b
mcodPos k (TMu a) =
let a_open = opentl (opentt a (SVar (k))) (k) in parts a_open
mcodPos k _ = []
-- Helper function to fold a list of types into a single SAnd-chained type.
-- An empty list becomes STop, a single-element list is the type itself.
foldSAnd :: [STyp] -> STyp
foldSAnd [] = STop
foldSAnd [t] = t
foldSAnd (t:ts) = SAnd t (foldSAnd ts)
-- Generates all subsequences of the input list.
-- This is equivalent to generating the powerset.
subsequences :: [a] -> [[a]]
subsequences [] = [[]]
subsequences (x:xs) = let subs = subsequences xs
in subs ++ map (x:) subs
-- The main function to generate all SAnd combinations.
allMcod :: [STyp] -> [STyp]
allMcod types = map foldSAnd (subsequences types)
-- the missing case for the csub-mu rule:
saux k a (TMu b) | isJust (cspl2 (opentt b (SVar (k-1)))) = let
fresh_k = k - 1
b_open = opentl (opentt b (SVar fresh_k)) fresh_k
a_open_lis = mcodPos fresh_k a
a_open_combs = allMcod a_open_lis
testNeg t = fresh_k `elem` flttNeg True t
in
any (\a_open ->
if testNeg a_open then
let r1 = csub (fresh_k-1) (dropLabel fresh_k a_open) (dropLabel fresh_k b_open)
r2 = csub (fresh_k-1) (dropLabel fresh_k b_open) (dropLabel fresh_k a_open)
in r1 && r2
else csub fresh_k a_open b_open) a_open_combsThis is to ensure precise isomorphic left type can be located For example:
(mu a. (((Int -> ((a) & (((Int) & (Top)))))) & (Top)))
(mu a. (a -> (((mu b. (b -> ((Int) & (Top))))) & (Int))))
<: their merge
since the right type will be split exhaustively
the precise left type also needs some exhaustive splitting to be picked