Skip to content
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

Add more helper functions for working with (type-level) metadata #54

Open
kosmikus opened this issue Jun 14, 2017 · 1 comment
Open
Milestone

Comments

@kosmikus
Copy link
Member

See #53 for some examples.

fieldNames would be nice to have on the term-level.

IsRecordType would be nice to have on the type-level.

But also type functions for operating on / extracting aspects of the type-level metadata structure would probably be useful. E.g. type-level equivalents of moduleName, datatypeName, constructorInfo, constructorName, fieldName.

@kosmikus kosmikus added this to the 0.3.2 milestone Jun 14, 2017
@kosmikus
Copy link
Member Author

I tried looking at this briefly while at the Budapest Haskell Hackathon.

Unfortunately, naming issues hit again. Let me try to organize my thoughts a bit.

Currently, we have the following identifiers:

-- term level metadata:
data DatatypeInfo :: [[*]] -> *
data ConstructorInfo :: [*] -> *
data FieldInfo :: * -> *
type ModuleName = String
type DatatypeName = String
type ConstructorName = String
type FieldName = String
moduleName :: DatatypeInfo xss -> ModuleName
datatypeName :: DatatypeInfo xss -> DatatypeName
constructorInfo :: DatatypeInfo xss -> NP ConstructorInfo xss
constructorName :: ConstructorInfo xs -> ConstructorName
fieldName :: FieldInfo a -> FieldName
datatypeInfo :: HasDatatypeInfo a => proxy a -> DatatypeInfo (Code a)
-- type level metadata:
kind T.DatatypeInfo :: *
kind T.ConstructorInfo :: *
kind T.FieldInfo :: *
type T.DatatypeName = Symbol -- unfortunately works only in GHC >= 8
type T.ModuleName = Symbol -- unfortunately works only in GHC >= 8
type T.ConstructorName = Symbol -- unfortunately works only in GHC >= 8
type T.FieldName = Symbol -- unfortunately works only in GHC >= 8
class T.DemoteDatatypeInfo :: T.DatatypeInfo -> [[*]] -> Constraint
class T.DemoteConstructorInfos :: [T.ConstructorInfo] -> [[*]] -> Constraint
class T.DemoteConstructorInfo :: T.ConstructorInfo -> [*] -> Constraint
class T.DemoteFieldInfos :: [T.FieldInfo] -> [*] -> Constraint
class T.DemoteFieldInfo :: T.FieldInfo -> * -> Constraint
type family DatatypeInfoOf :: * -> T.DatatypeInfo

I would like to add type-level equivalents of moduleName, datatypeName, constructorInfo, constructorNames, fieldName, but what should they be called?

type family GetModuleName :: T.DatatypeInfo -> T.ModuleName
type family GetDatatypeName :: T.DatatypeInfo -> T.DatatypeName
type family GetConstructorInfo :: T.DatatypeInfo -> [T.ConstructorInfo]
type family GetConstructorName :: T.ConstructorInfo -> T.ConstructorName
type family GetFieldName :: T.FieldInfo -> T.FieldName
  1. I would like to use the "same" names as on the term level, but we cannot, because T.ModuleName is already taken for the kind. In theory, we could use ModuleName for the extractor function and T.ModuleName for the kind, but I'm not sure if that's worth it.

  2. A minor annoyance is that I called the extractor function for constructors constructorInfo and not constructorInfos, because it sounded grammatically better and the only useful function seemed to be the one returning all of them. However, for demotion, I have DemoteConstructorInfo and DemoteConstructorInfos ...

  3. I would also like to include fieldInfo function that obtains information about the field names, but it's not
    quite clear how that should be typed. Field info is only present for record constructors. Ideally, we would
    want that to be enforced statically (and we can, with type-level metadata). But the code of a type does
    not contain this information. So fieldInfo, unlike any of the other selectors, will have to refer to the
    original type somehow. By far the most common use case seems to be for product types containing field
    labels, so then it should be something like:

    fieldInfo :: (IsRecordType a xs fields) => proxy a -> NP FieldInfo xs

    But this seems so different in style to the other selectors that I'm not sure if it should be in the same
    naming scheme / defined in the same place. Of course, one could argue that some of the other selectors
    should or could also be defined in terms of the original datatype, e.g.,

    moduleName' :: (HasDatatypeInfo a) => proxy a -> ModuleName
    datatypeName' :: (HasDatatypeInfo a) => proxy a -> DatatypeName
    constructorInfo' :: (HasDatatypeInfo a) => proxy a -> NP ConstructorInfo xss

    But then we either need to make a backwards incompatible change and remove the old functions (which could still be useful in some situations), or we need yet more names for all these identifiers ...

Thoughts welcome.

/cc @phadej @edsko

@kosmikus kosmikus modified the milestones: 0.3.2, 0.3.3 Nov 22, 2017
@kosmikus kosmikus modified the milestones: 0.3.3, 0.4.1 Sep 24, 2018
@kosmikus kosmikus modified the milestones: 0.4.1, 0.5.1 May 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant