-
Notifications
You must be signed in to change notification settings - Fork 563
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
Can't solve constraints in values which came from constructor binders where the constructor was polymorphic #4196
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't think of a reason why there would be a problem doing this. Those revised error output seem like improvements too! 👍
How exactly does this get used? I've tried adding: instance Con
x = test (Identity (2 :: Con => Int)) and I get: Could not match constrained type Con => Int with type Int while trying to match type Int with type Con => Int while checking that expression Identity 2 has type Identity (Con => Int) in value declaration main Is there a different way to construct values with constrained types that can be used in polymorphic constructors, and if not, is this feature then incomplete? |
Good point, originally I was just messing around with deferring execution of expressions automatically (similar to https://github.com/natefaubion/purescript-call-by-name I believe), and found it surprising that using Identity would not work. I was using FFI to construct these values which meant I never actually tested creating them in-language. I'll have a look to see if it makes sense to allow constructing such values naturally |
@rhendric It's possible, although you have to be explicit about the type of -- compiles fine in the pull req, with inferred type Con => Int
test2' = test2 ((Identity :: (Con => Int) -> Identity (Con => Int)) 10) The changes required to not need that hint are too great, I think It's actually possible to write the original test2 :: Con => Identity (Con => Int) -> Int
test2 (Identity (a :: Con => Int)) = a |
What about: test :: Con => { foo :: Con => Int } -> Int
test x = x.foo Is there a way to annotate that to make it work? Then there's this little puzzle: -- doesn't work
unid1 :: Identity (Con => Int) -> (Con => Int)
unid1 = coerce
-- works
unid2 :: Identity (Con => Int) -> (Con => Int)
unid2 = coerce :: forall a. Identity a -> a I guess I'm broadly concerned that the whole impredicative types question hasn't been exhaustively thought out in PureScript (considering interactions with function types, data constructors and destructors, records, arrays, anything else that gets somewhat special handling that I'm missing right now), and even though this seems like a harmless and, to a limited audience, beneficial enhancement to type inference, I'm not confident that it implements, or gets us closer to, a set of inference rules that would be straightforward to explain to a learner. It could easily be that in that respect, this change doesn't make the situation any worse—I'm just asking the broad question and hoping that someone with a stronger type theory background can say that it does or doesn't. |
Before this change, you couldn't solve constraints in values which came from constructor binders where the constructor was polymorphic:
This is because we weren't applying substitutions when checking the types of 'Var' exprs before subsumption, and polymorphic types like Identity get instantiated with unknowns during binder inference. This change adds the substitution in.
Checklist: