Skip to content

Logic subtyping and overloading #286

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 43 commits into
base: hkmc2
Choose a base branch
from
Draft

Conversation

auht
Copy link
Contributor

@auht auht commented Feb 26, 2025

2025-02-26 TODO:

  • Add spaces like a civilized person
  • Check intersections for WFedness
  • Remove assumption that only the first argument needs disjointness
    • Deal with nested dss
  • Support generalization (update collectTVs)
  • Add records (for now use temporary syntax fun foo: ["x": Int, "y": Int])

2025-03-06 TODO:

  • don't duplicate when LB is TV on same or higher level, in which case you can make both vars bound each other (same level) or the other one bound the LB
  • properly update type simplifier (and remove kludge)
  • remove use of nondeterministic collections

Later:

  • During simplification, take UBs into account to reduce things

2025-03-13 TODO:

Later:

  • use different propagation rules for TVs of same level
  • add an option to enable/disable :logicSub

@LPTK LPTK force-pushed the logic-subtyping branch from ab2a68a to 8bad1a5 Compare March 6, 2025 02:52

:todo
id of { x: 1 }
//│ Type: Str
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wat

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The { x: 1 } is elaborated to a Tup with an ascription ["x": 1].
It is typed as id("x") since the ascription is ignored.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why this happens. Are you sure it's an ascription? It should elaborate to a RecordField

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a Fld with the field asc set as Some(1).
Similarly, id of { x: 1, y: 2 } reports incorrect number of arguments. It is an error in basic/Records.mls originally.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I'll look into it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it's working "as intended". Currently, curly braces are equivalent to an indented block. Here one would need normal parentheses instead

id of (x: 1)

Comment on lines 152 to 157
//│ Type: ['x, 'scrut, 'eff, 'cons] -> 'x ->{'eff} 'cons
//│ Where:
//│ 'x <: ¬Int ∨ Int
//│ 'x#Int ∨ ∧ ⊥<:'eff ∧ 'scrut<:Int ∧ Int<:Int ∧ Str<:'cons
//│ Int ∧ 'x <: 'scrut
//│ 'scrut#Int ∨ ∧ ⊥<:'eff ∧ 'scrut<:Int ∧ Int<:Int ∧ Str<:'cons
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For patmat without default cases, can't we just implicitly add a case that matches the negations of all previous patterns and constrains the scrutinee to be Bot?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This inferred type scheme, like the original one from BbML, misinterprets the patmat as being exhaustive, thus allowing 'x = ~Int as a – spurious – solution.)

@@ -17,15 +17,15 @@ fun id(x) = x


run(x `=> id(x) `* x)
//│ Type: Int -> ⊥
//│ Type: -> ⊥
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔

//│ Type: Prod[Tru, Tru] | Prod[Fls, Fls]

:e
{ fst: y(x => x), snd: y(x => x) } as [ fst: Tru, snd: Tru ] | [ fst: Fls, snd: Fls ]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why you use a record on the LHS and tuples on the RHS? Why are the RHS' treated like records? They should be one-element arrays. Remember that [ fst: Tru, snd: Tru ] is syntax sugar for [ (fst: Tru, snd: Tru) ].

fun y: Any -> Tru | Fls
//│ Type: ⊤

prod(y(x => x), y(x => x)) as Prod[Tru, Tru] | Prod[Fls, Fls]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come this type checks? Shouldn't it be Prod[Tru | Fls, Tru | Fls]?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because classes are merged in union. It is actually Prod[Tru | Fls, Tru | Fls] here.
The example using record does not type check.
The original paper uses tuple and type checks: $(y(\lambda x.x), y(\lambda x.x)): (True \times True) \lor (False \times False)$

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait why does it type check in the original paper, then? Do they merge the union?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, it is because both $y$ are applied on the same argument $\lambda x.x$, and thus have the same return type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow... that seems a bit crazy. Do they keep track of equalities between terms at the type level? Or what other sorcery do they use? It sounds very expensive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they use the maximal sharing canonical forms to do the type checking, so the expression is something like

bind a = y in
bind b = x => x in
bind c = a(b) in
bind d = (c, c) in
d

Where c can be either True or False.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right; I remember seeing this. Presumably, we could do the same thing, but that would probably not be worth it. Please document this as comments on the test case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants