Skip to content
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

Investigate constraining behaviour #85

Open
nsbgn opened this issue Mar 13, 2022 · 6 comments
Open

Investigate constraining behaviour #85

nsbgn opened this issue Mar 13, 2022 · 6 comments

Comments

@nsbgn
Copy link
Contributor

nsbgn commented Mar 13, 2022

Consider this:

    TypeSchema(lambda x, y, z: F(x, x) ** z[F(x, A)]).apply(F(A, A))

... does not yield F(A, A)

    TypeSchema(lambda x, y, z: F(x, x) ** z[F(x, x)]).apply(F(A, A))

does yield F(A, A).

The logic for unifying with constraints doesn't make full sense. Why would it be okay to unify with base types, but not with variables?

Also, we should make sure that the following works:

    TypeSchema(lambda x, y, z: F(x, y) ** z[F(x, A), F(y, A)]).apply(F(A, A))
nsbgn added a commit that referenced this issue Mar 13, 2022
@nsbgn nsbgn added this to the Version 0.2: RDF support milestone Mar 14, 2022
@nsbgn
Copy link
Contributor Author

nsbgn commented Mar 14, 2022

A better way might be to explicitly indicate whether a subtype is acceptable, perhaps by having x[A, B] mean something different from x[+A, B] (where the + indicates that a subtype is accepted. Or perhaps automatically unfold concrete types in constraints to all their subtypes. I need to think through the ramifications.

@nsbgn
Copy link
Contributor Author

nsbgn commented Mar 15, 2022

Unfolding the concrete types seems the most workable. I would just need to register the subtypes of every base type operator and add a .subtypes() method on TypeInstances.

@nsbgn
Copy link
Contributor Author

nsbgn commented May 5, 2022

While the above is a good idea, it becomes complicated when coupled with intersection and union types (#79), since A.subtypes() should include A & B, and A & B & C, and... Though this might not be a problem since we can disregard them.

@nsbgn
Copy link
Contributor Author

nsbgn commented May 8, 2022

Plan of attack:

  • Don't have special notation for subtypes and supertypes, nor unfold types into its super-/subtypes. Instead, assume that every type also stands for its subtypes, just as we do now. I think this is almost always what you want, so there's no point in increasing the number of checks we do.
  • We now unify with the skeleton of the last remaining type in the constraint. Instead, we should unify with the entire type, excepting base types that have any subtypes and that are not already bound on the left hand side. In the latter case, we still consider the constraint satisfied and just put a new constraint on that one variable.
  • In case there are multiple types in the constraint, but they all have the same type operator, we can already unify with that operator, in case that narrows down other constraints.

Start with tests.

nsbgn added a commit that referenced this issue May 9, 2022
@nsbgn
Copy link
Contributor Author

nsbgn commented May 11, 2022

We use x[A] to mean that 'once x is bound, we must check that it is subtype of A', and we use x[y,z] to mean that 'once we are sure that x can only possibly unify with one of the constraint options (y or z), we can perform that unification'. This mixes up ideas: If one of the options is bound before the final option unification is triggered, it has turned into a subtype guard and won't unify to a concrete type anymore. If it is bound after, then it has already unified so we immediately get a concrete type. Also, it is unclear what A[x] would mean: must we check that x is a supertype of A once it is bound, or can we immediately bind x>A?

All this does not amount to sane behaviour.

This is why we should only accept the second idea, and when we want to be able to express a subtype guard, we must be explicit about it. How is still up for debate.

(x[~Qlt]) >> x
(x[+Qlt]) >> x
(x < Qlt) >> x
(x[Sub(Qlt)]) >> x
(x[Qlt.sub()]) >> x

x <= Qlt is the most intuitive, but it would need reinterpretation of the < operator, and I don't know if we ever need to combine the two (e.g. x[A, Subtype(B)]).

@nsbgn nsbgn mentioned this issue May 11, 2022
nsbgn added a commit that referenced this issue May 12, 2022
nsbgn added a commit that referenced this issue May 12, 2022
This renaming is done so that the `.subtypes()` and `.supertypes()`
methods become available for `Type`s. This is helpful for #85, since it
means we can generate sub/supertypes on demand.
nsbgn added a commit that referenced this issue May 12, 2022
@nsbgn
Copy link
Contributor Author

nsbgn commented May 12, 2022

Combining makes sense to do like so: (y < B) & x[A, y] or x[A, _ < B]

nsbgn added a commit that referenced this issue May 14, 2022
nsbgn added a commit that referenced this issue May 15, 2022
@nsbgn nsbgn removed this from the Version 0.2: RDF support milestone Nov 2, 2022
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

No branches or pull requests

1 participant