Subtyping Soundness and Counter-example Investigation [by May 16 discussion on Discord]
Summary of Current Status
The primary goal is to establish the soundness of a “translate subtyping” approach, particularly its relationship with a declarative subtyping system for recursive types. A key challenge has emerged: a specific counter-example demonstrates a subtyping relation that holds in the translate (algorithmic) system but for which a derivation in the declarative system (using transitivity via a middle type) has not been found. This potentially breaks the completeness of the declarative system with respect to the algorithm (algo => decl
).
Core Problem: Discrepancy between Algorithmic and Declarative Subtyping
The problematic subtyping relation is:
mu a. (mu b. Top -> Int) & mu a. (mu b. a -> Bool)
<: Yes (in translate subtyping)
mu a. (mu b. (b -> Int) & (a -> Bool))
Issue:
It’s proving difficult to find a “middle type” M
in the declarative system such that:
LHS <: M
and M <: RHS
where LHS
is mu a. (mu b. Top -> Int) & mu a. (mu b. a -> Bool)
and RHS
is mu a. (mu b. (b -> Int) & (a -> Bool))
.
Failed strategies to find a middle type:
- “Merge then subtyping”:
LHS <: mu a. ((mu b. Top -> Int) & (mu b. a -> Bool))
Then this intermediate type<: No (by nominal unfolding) RHS
. (This step is problematic because the negative occurrence ofa
forbids merging themu b.
binders if they are not equivalent, which they aren’t here due toTop
vsa
). - “Subtyping then merge”:
LHS <: mu a. (mu b. b -> Int) & mu a. (mu b. a -> Bool)
(This subtyping holds) Thenmu a. (mu b. b -> Int) & mu a. (mu b. a -> Bool) <: mu a. ((mu b. b -> Int) & (mu b. a -> Bool))
(Again, negativea
forbids mergingmu b.
). Then this intermediate type<: No (by nominal unfolding) RHS
.
Root Cause of Difficulty: The example involves a combination of:
- Nested recursive types (
mu a. (mu b. ...)
) - A weakly positive comparison (
b < Top
) - A negative comparison (
a <: a
) - Critically, a contravariant occurrence of
Top
being compared with a contravariant type variablea
.
Related Challenges
-
Soundness Proof for Type-Directed Casting:
- If pursuing a direct soundness proof with translate subtyping for a type-directed casting semantics (e.g., BCD-style), issues arise with un-invertible translated types.
- For instance, in a BCD disjointness rule (
B1 <| B |> B2
,A*B1
,A*B2
⇒A*B
), ifB
is a recursive type, splitting it at the translated type level can lead to types that don’t cleanly map back to simpler source types, complicating proofs. - Example: Translating
mu a. (a -> Int) & (a -> Bool)
gives[a. {a:(a->Int)&(a->Bool)}->Int & {a:(a->Int)&(a->Bool)}->Bool]
. Splitting this yields components like[a. {a:(a->Int)&(a->Bool)}->Int]
. For this to be useful as an intermediate step mapping to the source, it needs to be rewritten/correspond to[a. {a:(a->Int)}->Int]
(i.e.,mu a. a -> Int
).
-
Operational Semantics:
- Lack of concrete operational semantics makes it hard to determine definitively if the problematic subtyping should hold by constructing terms.
Positive Developments
- Generalized Structural Unfolding Lemma:
- A more generalized structural unfolding lemma has been proven, which is simpler than the JFP version, thanks to polarized substitution and translate subtyping.
- JFP version:
If mu a. A <: mu a. C <: mu a. D <: mu a. B then A [a |-> mu a. C] <: B [a |-> mu a. D]
(middle typesmu a. C
,mu a. D
must be recursive). - New version:
If mu a. A <: C <: D <: mu a. B then A [a |-> C] <: B [a |-> D]
(no restriction on middle typesC
,D
being recursive). This is beneficial for encoding.
Proposed Paths Forward / What to Try Next
-
Deeper Dive into the Counter-example:
- Attempt to find an alternative middle type in the declarative system that was not yet considered.
- todo Explore coercive semantics (e.g., by trying to write Haskell functions) to gain intuition about whether the subtyping should practically hold.
-
Modify/Refine the Declarative Subtyping System:
- Option A: Extend Declarative Rules: Extend Declarative Rules
- Investigate adding new rules or modifying existing ones (e.g., Amber rules, nominal unfolding) to make the declarative system more powerful to cover the counter-example. This aims to restore
algo => decl
completeness. - Consider developing BCD-style rules for recursive types directly at the source level.
- Investigate adding new rules or modifying existing ones (e.g., Amber rules, nominal unfolding) to make the declarative system more powerful to cover the counter-example. This aims to restore
- Option B: Restrict Subtyping (make it less expressive but potentially more regular):
- Idea: Identify and exclude “corner cases” that are practically irrelevant but cause theoretical difficulties. The key case is
mu a. Top -> a <: mu a. a -> a
(or more generally,Top
vs. a type variablea
in contravariant positions). - Mechanism in Nominal Rules: Source Subtyping
- Augment the
mu-sub
rule:T |- [{a:A}/a]A <: [{a:B}/a]B
Check a A B
Check a A B
would be a predicate that detects problematic comparisons likea <:- Top
(variablea
on LHS of subtyping againstTop
on RHS, in a contravariant context derived from unfolding).
- Augment the
- Mechanism in Target Type Subtyping (Translate Subtyping):
- Introduce polarized subtyping (
<:+
,<:-
) and polarized well-formedness (T |-+ A
,T |-- A
) for target types (which are non-recursive). - This would enforce that labelled types (resulting from translating contravariant recursion variables) only appear in negative positions.
- The subtyping rule
{a : A} <:- Top
could be rejected by such a polarized system.
- Introduce polarized subtyping (
- Impact: This might simplify the system and proofs, but one must verify that essential expressive power and properties like transitivity are not lost.
- todo play in haskell
- Idea: Identify and exclude “corner cases” that are practically irrelevant but cause theoretical difficulties. The key case is
- Option A: Extend Declarative Rules: Extend Declarative Rules
-
Refine the Translation and Target System Properties:
- Stronger Well-Formedness for Target Types:
- Develop stricter well-formedness criteria for types in the target language. The goal is to ensure that any type arising during a subtyping derivation in the target language (especially intermediate types from splitting) must correspond to a well-formed source type.
- This could prevent the generation or use of “ill-formed” intermediate target types (those not invertible to a source type) in proofs that require mapping back to the source system.
- If a target type
T_m
is used as a middle type in|A| <: T_m <: |B|
,T_m
should be “invertible” or correspond to some source typeS_m
such thatA <: S_m <: B
could be considered. - This could address the “un-invertible types” from splitting, as types like
[a. {a:(X&Y)}->Z]
(from splitting) might be deemed ill-formed if they can’t be related back to something like[a. {a:X}->Z]
.
- Stronger Well-Formedness for Target Types:
-
Direct Soundness Proof Strategy:
- Continue pursuing a direct proof of type soundness using the algorithmic (translate) subtyping, leveraging the new generalized structural unfolding lemma.
- This path might bypass the need for proving full equivalence with a declarative system if direct soundness can be shown.
- Requires tackling the issue of un-invertible translated types in the context of the chosen operational semantics (e.g., type-directed casting).
Also related to Can we use the unfolding lemma to reject this example?
-
Encoding Considerations:
- Homogeneity: If the generalized structural unfold rule (with type annotations
A+
,A-
) is necessary for encoding operations likesubst
, ensure the same generalized strategy is applied consistently for other operations (eval
,double
) for a “homogeneous” encoding. ( todo Tony to double-check this). - Investigate if a similar generalization is needed for
fold
operations. Current thinking is no, becausefold
applies to supertypes, whileunfold
deals with subtypes (like intersections).
- Homogeneity: If the generalized structural unfold rule (with type annotations
Attempts
What is the case in the most general setting? Equi-recursive Amber + distributivity rule
mu a. (mu b. Top -> Int) & mu a. (mu b. a -> Bool)
<: mu a. (mu b. (b -> Int) & (a -> Bool))
a1 & a2 <: a'
|- (mu b. Top -> Int) & (mu b. a2 -> Bool) <: mu b. (b -> Int) & (a' -> Bool)
a1 & a2 <: a', b1 <: b'
|- (Top -> Int) & (a2 -> Bool) <: (b' -> Int) & (a' -> Bool)
(X) Does not seem to work
Can we use the unfolding lemma to reject this example?
A1 = Top -> Int
A2 = a -> Bool
B1 = b -> Int
(mu a. (mu b. A1)) & (mu a. (mu b. A2))
<: (mu a. (mu b. B1 & A2))
question, what is the unfolding lemma in the presence of distributive subtyping?
- Is it the form we have proved?
- What is the operational semantics?
Cf. Qianyong’s work, is disjointness enforced in the typing rule?
Extend Declarative Rules
Attempt:
--------------- mu-dist
mu a1 ... an. A & mu a1 ... an. B <: mu a1 ... an. A & B
so we could go for subtyping then merge (simultaneously on two binders)
mu a. (mu b. Top -> Int) & mu a. (mu b. a -> Bool)
<: mu a. (mu b. b -> Int) & mu a. (mu b. a -> Bool)
<: mu a. (mu b. (b -> Int) & (a -> Bool))
However, the rule is not admissible (unsound) in the translate system
(nested recursion requires the inner translation to be invariant rather than invariant)
also, as the second subtyping is not accepted by the algorithm, the rule should not attempt to include what wasn't included in the algorithm, but rather attempt to accept the original two types on LHS and RHS
Restrict the subtyping
Source Subtyping:
prevent: The key case is
mu a. Top -> a <: mu a. a -> a
(or more generally,Top
vs. a type variablea
in contravariant positions)
Source:
A [a |-> {a : A}] <: B [a |-> {a : B}]
Check Pos a A B
----------------------------
mu a. A <: mu a. B
+-----------------+
| Check Pos a A B |
+-----------------+
-----------------------
Check Pos a a <: Top
-----------------------
Check m a b <: Top
Check m a (A[b |-> {b : A}]) (B[b |-> {b : B}])
----------------------- mu?
Check m a (mu b. A) (mu b. B)
- We have built-in transitivity in the source, so this is not a concern
Target Subtyping:
Target
|-+ A
-----------
A << Top
+--------+
| |-m A |
+--------+
|-+ A
-------------
|-+ {a : A}
|-m ... for rest of the cases
- We should be able to prove a stronger regularity lemma for the target subtyping, so transitivity for the target subtyping should also be fine
- Benefit: since we only modify the well-formed ness, if we manage to prove transitivity, then all the properties (e.g. generalized unfolding lemma) should still hold in the target system
- Question: is the new rule still sound?
- Question: it helps with the subtyping, how about the whole completeness proof?
- we will need to write a stronger polarized substitution lemma
- The hope: no more
a weakpos in A << B
, where there could be negative a inB
, but we knowa in fv_pos(B)
, so any rewriting for B will be equivalent and we can transfer B back to an invertible type
Encodings
Heterogeneous structural rule
In Encoding CP + negative methods, we propose:
e : A+
A+ <: A- <: mu a. B
--------------------- polarized structural unfolding
unfold [A+, A-] e : B [a+ |-> A+, a- |-> A- ]
B [a+ |-> A+, a- |-> A- ]
=(B [a+ |-> A+]) [a- |-> A-]
a is not free (A)
(B [a+ |-> A+]) [a- |-> A-]
= (B [a- |-> A-]) [a+ |-> (A+ [a+ |-> A-])]
= (B [a- |-> A-]) [a+ |-> A+]
B [a+ |-> A+, a- |-> A- ]
mu a. A ~~~> [a. A [a- |-> { a : A } ] ]
trans2 C D ->
trans2 (subst_tt_m mode X C A) (subst_styp_m mode X D B).
mu a. A [b+ |-> C]
~~> [a. A [a- |-> { a : A } ] ] [b+ |-> D]
== [a. (A [b+ |-> D]) [a- |-> { a : A } [b- |-> D] ] ]
We could dually, extend:
e : A [a |-> B]
mu a. A <: B
---------------
fold [B] e : B
If mu a. A <: B <: C <: mu a. D
then A[a |-> B] <: D [a |-> D]
to?
e : A [a+ |-> B+, a- |-> B- ]
mu a. A <: B- <: B+
--------------------- polarized structural folding
fold [B+, B-] e : B+
What will the generalized structural unfolding be like?
For reduction: unfold [A+, A-] (fold [B+,B-] v) ----> v
The typing derivation:
v : C [a+ |-> B+, a- |-> B-]
mu a. C <: B- <: B+
------------------
fold [B+, B-] v : B+ B+ <: A+
------------------------------------
fold [B+, B-] v : A+ A+ <: A- <: mu a. D
-----------------------------------------------------------------------------
unfold [A+, A-] (fold [B+, B-] v) : D [a+ |-> A+, a- |-> A- ]
The lemma should therefore be:
given:
mu a. C <: B- <: B+ <: A+ <: A- <: mu a. D
show: C [a+ |-> B+, a- |-> B-] <: D [a+ |-> A+, a- |-> A- ]
Proof attempt:
by translation:
C [a- |-> {a : C}] <: D [a- |-> {a : D}]
Case 1.
a is weakly positive in C and D
We can show:
C [a- |-> B-] << D [a- |-> A-]
Moreover, as B+ << A+
We can show:
C [a- |-> B-, a+ |-> B+] << D [a- |-> A-, a+ |-> A+]
trans2 A B ->
trans2 C D ->
trans2 (subst_tt_m mode X C A) ~~> (subst_styp_m mode X D B).
Case 2.
D <: C, C <: D
which implies that
mu a. C == mu a. D
mu a. C <: B+ <: B- <: A+ <: A- <: mu a. D <: mu a. C <: B+ <: B- <: A+ <: A- <: mu a. D
any types are equivalent
We can show:
C [a- |-> B, a+ |-> B] << D [a- |-> A-, a+ |-> A+]
since B, A-, A+ are just equivalent to mu a. C / mu a. D
However, the other dual forms, such as
e : A [a+ |-> B+, a- |-> B- ]
mu a. A <: B+ <: B-
--------------------- polarized structural folding (with B+ <: B-)
fold [B+, B-] e : B-
e : A-
A- <: A+ <: mu a. B
--------------------- polarized structural unfolding (with A- <: A+)
unfold [A+, A-] e : B [a+ |-> A+, a- |-> A- ]
Seems also fine to prove the structural unfolding lemmas (though they are not useful in the encoding)?
- Maybe what we need is something stronger than the structural unfolding lemma
- Maybe some dual forms are subsumed by other better ones