-
Notifications
You must be signed in to change notification settings - Fork 269
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
List instances for a type in GHCi #166
Conversation
This is awesome. It'd also be great if you could list the instances of a given class. |
@ElvishJerricco listing every instance of Eq ()
Eq Int
Eq ((), ())
Eq ((), Int)
..
Eq ((), ((), ((), .. edit ah same as |
@Icelandjack Would that just show this?
Anyway, I just realized you can already get this with |
Currently the Here is what the docs on the relevant method for -- Filter the instances by the ones whose tycons (or clases resp)
-- are in scope (qualified or otherwise). Otherwise we list a whole lot too many!
-- The exact choice of which ones to show, and which to hide, is a judgement call.
-- (see Trac #1581) Additionally, currently |
Thank you for opening a GHC proposal for this. After reading the proposal, I'm left with a number of questions:
|
Hi @RyanGlScott, thanks for commenting and raising some great points. I've made some changes to the proposal which should clarify things already but I'll respond here as well.
For 4-9, I've moved it to a future work section as well as expanded the sections and added an example for the traces. |
Thanks for the feedback @RyanGlScott. @xldenis gave a good response,
¹ Examples of type classes over
|
I've added a section for further examples as well as clarified what happens when a typeclass is provided as an argument to |
I might prefer writing constraints with wildcards, for sake of working with multi-parameter type classes or aggregate constraints. Basically, something like a prolog REPL |
@RyanGlScott I know you were busy with ICFP (congrats on your talk!), do you feel like your concerns have been addressed? @Ericson2314 I think we'll just use the same syntax as the |
I haven't reviewed the changes closely, but things look reasonable from a glance. Then again, I'm not part of the committee, so you don't need my permission to continue :) |
Well then I think I'll ping @nomeata to bring this before the comittee! As a summary of the changes that occurred throughout the discussion:
I don't believe there are any open objections to this proposal as it stands so it should be ready for committee review? |
Bump @nomeata :) |
Thanks for the bump, I guess it got lost during ICFP. |
I think I get the basic idea of what we'd like to do here, and it seems useful enough. However, I think the proposal could use a little more details on how things are supposed to work. In particular:
Sorry for the long post, I hope this will help things more precise. |
I rather agree with Iavor. The "proposed change specification" is not really a specification, in the sense of precisely specifying what should and should not happen. I think that the intent is something like this.
For example
I don't think there is any need for the Optional extra: allow named wildcards. So then |
@xldenis do you think you could make some changes to the proposal to clarify how things should work? |
Hi @yav, yes I was travelling over the past week so I didn't have time to address your comments but I just got back today so I'll push a revision of the proposal tomorrow. Response to @yav's and @simonpj's comments:
That was discussed and proposed at first but the intention at this point is to used type holes to represent variables in queries. Since it appears that parsing mechanism used in
I personally think that the
Out of the listed potential matches, here is what I would expect the command to return: Num b => C7 (a,[b],c) -- Matches head, can't simplify context (existential)
Num a => C8 (a,Int,c) -- Matches head, cant't simplify context (universal)
C9 (a,Char,c) -- context improves instance
C10 (a,b,Char) -- head matches, context unsatisfiable Notably, we also discharge the equality constraint for the last two instances. @simonpj I think your comment reflects the largest ambiguity / ux problem with this proposal:
As stated, the command would actually return any class instances for the type
So the output we'd expect would be something like: > :instances Eq (Maybe _)
Static (Eq (Maybe _))
.... @ElvishJerricco made the same mistake earlier in the thread, so this is not an isolated event. Obviously the proposal should be clarified but maybe there's something that could be done to avoid users confusing the command in ghci. |
proposals/0000-ghci-instances.rst
Outdated
Execution | ||
~~~~~~~~~ | ||
|
||
Provided with a valid type, ``instances`` will attempt to match it against the heads of all visible class instances and satisfy all the implied constraints. The output will consist of a formatted listing of all matching and satisfiable instances. Each instance should be simplified as much as possible, meaning that if an instance: ``(c ~ Bool) => C c`` were found it would be presented as ``C Bool``. |
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 don't know if I worded this properly, but the intent is to say that given: :instances T
, we look for all unifiable instances C T
, for all visible classes C
.
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.
Thanks for making the changes. Just one more clarification: the part about having to satisfy all implied constraints seems a little fishy to me. If I write:
:instances (Maybe _)
I would expect to see the Eq
instance, correct? The instance looks like this:
instance Eq a => Eq (Maybe a)
When deciding if it should display it, GHC will unify the head against my query, which will succeed. However, we can't simplify the context any further, as we are left with Eq a
and we don't know how to simplify this.
OTOH, if I'd written :instances (Maybe (_ -> _))
, then I probably wouldn't want to see that instance as there aren't any instances that match Eq (_ -> _)
.
So we need some sort of a rule that will tell us which left-over constraints are OK, as in the first example, vs. not OK as in the second.
My suggestion would be that an instance should be displayed if we can unify with the head, and then simplify the instance context to constraints that only involve variables. I haven't thought very deeply about that, so please take it with a grain of salt.
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.
OTOH, if I'd written :instances (Maybe (_ -> )), then I probably wouldn't want to see that instance as there aren't any instances that match Eq ( -> _).
Wouldn't this just be a matter of going through the normal instance resolution process? When we attempt to reduce the context GHC should tell us that there is no instance for Eq (_ -> _)
?
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.
Indeed.
The point I was trying to make is that in both examples (:instances (Maybe _)
and :instances (Maybe (_ -> _))
) we can't fully simplify the constraints in the instance context: in the first case we are left with Eq _x
and in the second with Eq (_x -> _y)
. But (I think?) we'd like to consider the first one matching and the second one not matching.
So we need some way to distinguish these two: one way would be the rule I suggested (the first one matches because the left-over constraints only mention variables, while the second one is rejected as it mentions a concrete type constrctor)
Another option would be to say that neither of these examples should match, which is what I think the current specification suggests, although I think that might be somewhat surprising. If that's the intention, let's add the example to the document to make it more explicit.
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.
Hmm, yea I see the problem now, I'll add that specific example and reword that sentence. What we'd like is effectively that only constraints on the type-holes remain after simplifying.
Wish list item: To generate
|
A suggestion for the MPTC syntax: use Notes:
cc @xldenis |
newtype Gen a = Gen (Int -> StdGen -> a) where
deriving
Functor
via
(Compose ((->) Int) ((->) StdGen)) It would be good to see
Sometimes instances have complicated constraints, like
but not |
I need to rebase my branch on the latest master but I expect that your example will work. @deepfire that seems like a pretty reasonable idea but I think we should revisit it once I've finished implementing the current proposal :) |
>> :instances Kleisli (f `Compose` Maybe) |
The proposal has been accepted; the following discussion is mostly of historic interest.
This is a proposal to add a GHCi command that lists all valid instances for a given complete or partial type signature.
Rendered