-
Notifications
You must be signed in to change notification settings - Fork 381
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
Confusing behavior when using a constraint name in interface parameters #3449
Comments
Also now conflicting names of parameters, arguments, and constraints behave differently failing "Mismatch between: Nat and Bool"
interface Iface (b : Bool) (b : Nat) where
-- Produce warning about shadowing
f : (b : Bool) -> (b : Nat) -> ()
-- Successful compilation without warning
interface (b : Bool) => (b : Nat) => Iface where |
I find it odd that function arguments can have the same names, because it's very unintuitive f : {b : Bool} -> {b : Nat} -> ()
g : ()
g = f {b = True} {b = 0} |
yeah that should probably not be allowed |
One more strange thing: f : {b : Bool} -> {b : Nat} -> ()
failing "While processing left hand side of f. Non linear pattern b"
f = ()
-- Successful compilation
f {b=_} = () |
So I've been playing with this for a bit in the past few days and my conclusion is that interface elaboration is subtly broken in very annoying ways. Like you point our, the way the constraints are elaborated is confusing, some parameters get lifted as arguments, sometimes shadowing each other. The conclusion I've come to is that elaborating constraints as record fields is problematic. They should be record parameters, or at least there should be a meta-operation to move fields into parameters and vice-versa to help with instance search. Do you think this would lead to a resolution of the problem? Let me know if you think this is going in the right direction of I'm off-base completely |
Anyway, it's not clear how this would solve the original problem. |
I don't think this solves the problem because all I'm suggesting is adding a warning here, and it's weird to change semantics just for the sake of it. So further my text is off-topic. However, making constraints parameters of the interface can be useful. In Haskell, each type can have only one instance of an interface, so constraints are resolved unambiguously. In Idris, implementations can have different constraints, and sometimes it is useful to specify this at the type level. A common example is One solution was suggested in #777 — the ability to make constraints parameters. Another solution was suggested in #3420 — auto-parameters, which are similar to constraints, and they are sufficient for interfaces with proofs. If I understand correctly, you are proposing to make all constraints implicit parameters. I'm not sure this would always work well, but I think it might be useful sometimes. In fact, this is a special case of the first solution. However, constraints also need to remain fields in order to be available at runtime. |
That is not the case! Parameters are available at runtime as long as they are not marked as |
Arguments of the record constructor for parameters are erased record X (n : Nat) where
constructor MkX
failing "While processing right hand side of getn. n is not accessible in this context"
getn : X n -> Nat
getn (MkX {n}) = n Main> :ti MkX
Main.MkX : {0 n : Nat} -> X n |
It took me a second to realise why my statement was wrong, but it's because the type constructor has the unrestricted multiplicity not the data-constructor. |
Steps to Reproduce
This code compiles successfully:
It may seem that the parameter depends on the constraint. But it doesn't. Currently, constraints depend on parameters, not the other way around. The
b
in a parameter is implicitly bound and has nothing to do with theb
in a constrain:We can try to prove it:
Expected Behavior
Warning or error
Observed Behavior
Successful compilation
The text was updated successfully, but these errors were encountered: