-
Notifications
You must be signed in to change notification settings - Fork 641
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
Interface issues: a tentative summary #3114
Comments
I've been through all of these now, and either fixed the misbehaviour, or established that Idris is doing the right thing (even if it is reporting the problem unhelpfully). The main issue we need to consider from the language design point of view is what to do about diamond shaped interface hierarchies. I'm not going to change the core language, which means there is no way Idris is going to deduce that, for example, x, y : Num a -> x = y, but we should put some thought into how properties of such hierarchies should be dealt with. |
I see the possibility of a "multiple inheritance" problem here, but I would expect such problem to shoiw up when interfaces are implemented, not when they are declared. The other thing is that, as I commented in #2497 and #3078, we have new errors with 0.11-git:7e7d0eb which I am not sure are directly related with this problem. |
@edwinb Can't diamond shaped hierarchies in this case be solved with linearisation ? |
@ahmadsalim I don't know what you mean by linearisation here... do you have an example? Do you mean making the hierarchy linear? I think that can help... Generally if you need a specific implementation you could be precise about it in the type too (e.g. parameterising by an implementation). The point is that Idris cannot make any assumptions about the path through an interface hierarchy, or whether one implementation is equal to another, purely based on types. The type theory doesn't support it, the possibility of named implementations further spoils it. |
@edwinb Yeah, exactly. Like the C3 linearisation. I understand the second part, which makes perfect sense. |
@ahmadsalim Yes, reasoning about instances can be annoyingly awkward at the moment. Does naming the constructor help? Perhaps giving access to the name somehow would be useful... |
@edwinb Sorry, it has been a long time now, but I thought that it might be a good idea to mention it while the idea was discussed. Perhaps giving access to the name might not be a bad idea :). |
I believe that #2233 mentions that it would be nice if manually created instances could somehow be registered in interface resolution, which could be another alternative. |
One syntax could be %hint implementation
a : P
a = ... Where |
This works: NatSemigroupAdditive : Semigroup Nat NatPlus
NatSemigroupAdditive = MkSemigroup undefined but not [NatSemigroup]
Semigroup Nat NatPlus where
composition_associative = undefined
(I'd be sorry to find out that the implementation shouldn't work as part of expected behavior. Oh well.) |
This compiles: interface SemigroupL (a : Type) (impl : Type) | w where even though Edit: I feel such "phantom" constraining parameters might have interesting uses if combined with named implementations or the "using" syntax. |
One very nice thing would be, given the following code, interface
(am : Monoid a zero add, mm : Monoid a one mul)
=> Semiring (a : Type) (zero : a) (add : Type) (one : a) (mul : Type)
| a, add, mul
where to make I'm not sure if that's actually sensible considering the scope for multiple implementations, but this: (eq : Eq a) => Eq (Vect n a) where
(==) = (===) @{eq} would really be nice. This kind of "parametric" generation of instances is moving into ML module functor territory, I suppose (although I don't know anything about those!), but it's really weird to be able to name the constraints in my first example and then not use them at all (outside of the determining parameters, as I've discovered: interface
(monoid : Monoid a e tag)
=> AbelianGroup (a : Type) (e : a) (tag : Type)
| a, tag, monoid {- e? -}
where This typechecks.) Edit: Oh, apparently the named constraints are available in some cases. But they're hard to work with. |
Here's an amusing one that seems like a bug or a syntax limitation. interface
( ring : Ring a zero add one mul
, ab : AbelianGroup' a one mul zero)
=> Field
(a : Type)
(zero : a) (add : Type)
(one : a) (mul : Type)
| a
where
(+...) : a -> a -> a
(+...) = (+..)
(*...) : a -> a -> a
(*...) = (*..) Trying to do a implementation Field Double 0.0 Add 1.0 Mul where
-- empty makes Emacs pronounce this implementation a hole. But adding a parameter implementation Field Double 0.0 Add 1.0 Mul where
lol = 1.0 works fine. |
I am completely lost with Idris interfaces at this point. To the issues mentioned in my original post, #3727 has come on board and has forced me to downgrade to 0.99. I thought that, first and foremost, interfaces were designed to improve code understandability and support name overloading. I do not understand the |
@nicolabotta I understand your frustration, and we highly appreciate your bug reports. Regarding, #3727 I think that this is currently a limitation in Idris which hopefully will be resolved at some point if we get better unification; a workaround is to inline the given type definition. |
Ahmad, could you please elaborate a little bit on #3727? I do not know a workaround for the issue and I am still torn between rewriting IdrisLibs to make it comply with 1.0 and staying with 0.99. If a workaround is available, I could try to upgrade without braking too much legacy code. Thanks for the I understand that Idris is a collaborative project. My frustration comes from the fact that the two basic idioms for organizing programs -- modules and interfaces -- have been struggling with more or less the same issues since years. This makes it very difficult (for me) to write maintainable code in Idris. It is possible that I am doing something fundamentally wrong, of course. Best, Nicola |
@nicolabotta The documentation for |
@nicolabotta I think I should say that it wasn't my intention to say "look, Idris is broken!" but rather to provide as much data as I could for people familiar with the internals. It was to help them figure out if there were any underlying causes that could be dealt with easily to fix a bunch of interface quirks at once. The problem is that many, many features have been added that are not on the Idris docs website (which, of course, I understand the reasons for) and they are obviously interacting in nontrivial ways whose shortcomings have not yet been identified completely -- especially since I think that most users exercise either the proofish/Agda side of things, or the low-level |
FWIW, an example of a diamond inheritance problem, taken from #3791: -- idris 1.0
-- idris --noprelude
module Main
interface A a where
p : a
interface A a => B a where
q : (x : a) -> (x = Main.p) -> a
interface A a => C a where
interface (B a, C a) => D a where
e : (x : a) -> (y : x = Main.p) -> q x y = Main.p ...producing:
|
@atacratic It works in Idris 1.2 if you define C first and then B. Or equivalently, if B and C were defined in separate modules, it works if you import C first, then B. module Main
interface A a where
p : a
interface A a => C a where
interface A a => B a where
q : (x : a) -> (x = Main.p) -> a
interface (B a, C a) => D a where
e : (x : a) -> (y : x = Main.p) -> q x y = Main.p
implementation A Integer where p = 42
implementation B Integer where q x _ = x
implementation C Integer where
implementation D Integer where e x y = y
test : 42 = 42
test = e 42 Refl |
There are a number of open issues on interfaces that make it difficult to use interfaces and interface implementations. Some of these issues have been around for a while, others are relatively new. I am going to use this post to collect what seem (to me) the most obvious misbehaviors. I hope that this summary can help tackling the problems that affect interfaces more effectively. I am listing first those issues that seem more severe to me.
1) The type checker does not recognize certain
Num
implementations. This is issue 2830. On a fresh installation of https://github.com/nicolabotta/SeqDecProbs,you should be able to do
and get something like
Replacing line 25 of "NonNegRationalTest.lidr" with
makes the program type check.
2) The type checker rejects multiple constraints that are refinements of the same interface. This is issue 2497. It makes it very cumbersome to use interfaces to define new interfaces and requires users to implement linear hierarchies like
instead of the more natural
Please, see also issue 2498 and 3078!
3) Trivial interface declarations fail to type check with less than useful error messages. This is issue 2505. Since I first came across this problem, the error message has changed but has not become more understandable (to me). Please, see also issue 2053.
4) Implementing
Show
for sequences of dependent pairs: how to do it? This is issue 3113. Please also note the error message referring toPrelude.Show.idr
!The text was updated successfully, but these errors were encountered: