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
Provide a primitive to show types as Symbols #164
Conversation
My first thought was that yes, of course we should do something like this! Then I realized that one could easily construct a program that only compiles if GHC formats a type in a particular way. Hrmm. Then my biggest concern hit. |
@treeowl, I don't quite see what the complicated inference case would be. My concern is more around @treeowl 's first concern, about compilation depending on GHC's choice for rendering types. I'm also lost at the proposal's "it will emit a derived constraint |
@goldfirere, I don't have a fully worked example. My concern is that someone may try to show a type that has metavariables in it. What's supposed to happen then? If the result depends on details of the type checking process, that sounds much too wild to me. What if the result of showing the type somehow determines the values of one or more of those variables? If that's possible, it sounds twisted. |
I'm assuming that |
@goldfirere, that seems like an eminently reasonable restriction. It is, however, quite different from what |
Good point -- this new feature couldn't be used to implement today's |
@treeowl @goldfirere thanks for your comments. Would you be more supportive of the proposal if it came with a specification for how the type were printed, an if |
@isovector, that would certainly help. You'll also either have to ban higher-rank types or specify precisely how to deal with them. I think you should also remove the claim that this can be used to implement |
I would greatly appreciate this feature. I've often wanted to have a type-level set backed by a sorted type-level list, and have been unable to do so as |
@parsonsmatt No, you would erroneously equate types which have equal names but come from different modules/packages. What you want is type-level fingerprinting à la |
@nomeata ready for committee eyes. Thanks!! |
Before making a recommendation to the committee, I have a few questions:
1. Let's suppose that every Haskeller who wrote a type definition also wrote type instances for `ShowTypeSymbolPrec`, both for the type itself and for any promoted data constructors. Then could this be all implemented in user-land, just with ordinary type families? I foresee needing an infinite number of instances to deal with Symbols and Nats, as well as some magic around the differentiation between lists/tuples and other constructors. Otherwise, it looks possible. Do you agree?
2. Presumably, this feature would look through type synonyms. (Anything else would break type safety.) So, `ShowType String` yields `[Char]`. This has the potential to break abstraction barriers, allowing packages to see how other packages implement their (abstract) types. This means that a package that believes it's upholding the PVP might inadvertently cause downstream breakage when performing a (supposedly purely internal) refactor. Do you agree?
3. How does ShowType deal with types that are not in scope? This could happen because the types were inferred, or due to type synonym/type family expansion. We can't have ShowType behave differently in different modules, so it would have to either (A) render every type with its package and module prefix or (B) always omit package and module prefixes. Choice (B) is much more pleasant to use, but it's potentially ambiguous, if there are multiple types of the same name in play. What are your thoughts here?
Thanks!
|
Replying to point 2: Shouldn't changing a type synonym be considered a breaking change? Are you thinking about a more complex situation? |
I agree with @Lysxia. Type synonyms aren't a proper abstraction mechanism anyway. |
@goldfirere, I think we want |
|
What if instead of
With a magic instance for Given only I think we can already approximate that using
The proposal suggests that it generalizes the current |
I support @Lysxia idea of |
I spent a good chunk of yesterday playing around with edited a few times: @int-index there's a bit of a problem with adding |
Thanks for the clarifications @isovector. Yes, I was just wrong about my point (2) on type synonyms -- sorry! I would be ready to make my recommendation to the committee here, but it seems like more revisions are in the works. I'll wait until things settle down again. |
As this has planned updates, I've removed the "under review" label. Please resubmit when ready. |
Based on @Lysxia's suggestion, I've come up with the following formulation. Wondering if anyone has feedback on this before I go through the work of updating the proposal proper. {-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
module Proposal where
import GHC.Generics (FixityI (..), Associativity (..))
import qualified GHC.TypeLits as TL
data Datatype = Datatype
{ datatypeName :: TL.Symbol
, datatypeFixity :: FixityI
, moduleName :: TL.Symbol
, packageName :: TL.Symbol
, isNewtype :: Bool
}
data Constructor = Constructor
{ conName :: TL.Symbol
, conFixity :: FixityI
, conDatatype :: Datatype
}
data TypeInfo
= Data Datatype
| Promoted Constructor
| Symbol TL.Symbol
| Nat TL.Nat
type family TyRep (t :: k) :: TypeInfo
type family ShowSymbol (t :: TL.Symbol) :: TL.Symbol
type family ShowNat (t :: TL.Nat) :: TL.Symbol In particular, the proposal would be to provide the bottom three type families as GHC primitives, and relegate the work of showing more complicated types to be built out of these in library code. |
@isovector How are you going to represent I suggest following the structure of |
I understand that you can skip type families here, but what about data families? Classes? Functions? I worry that this will spiral out of control and end up replicating the existing features of generics... |
I want to add that I would really like to see GHCi using this type family for |
@jvanbruegge that seems unlikely since |
Closing this for personal reasons---if anyone else would like to take up the mantle, that'd be cool! |
ShowType
has an annoyingly specific kind:k -> ErrorMessage
. If we had something similar whose kind were insteadk -> Symbol
, we could use it in many more places.Rendered