Opened 3 years ago

Closed 3 years ago

#5406 closed feature request (fixed)

Template Haskell: Reification of type family instances

Reported by: reinerp Owned by:
Priority: normal Milestone:
Component: Template Haskell Version: 7.0.4
Keywords: Cc: alfonso.acosta@…, illissius@…, Ashley, Yakeley, SamAnklesaria
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Difficulty:
Test Case: Blocked By:
Blocking: Related Tickets:

Description

In Template Haskell, there's no way to find out all instances of a type or data family. Manuel commented on this in an old patch (third dot-point):

Tue Mar 24 20:34:47 PDT 2009  Manuel M T Chakravarty <chak at cse.unsw.edu.au>
  * Template Haskell: make reify aware of type families
  Ignore-this: 4b9c2d626e7c506a74331bb91d0fcff7
  - Reifying a type family returns a TH family declaration
  - Reifying a data constructor from a data instance attributes that
    constructor to the family (not the representation tycon)
  - Ideally, we should have facilities to reify all type/data instances of a 
    given family (and the same for instances of a class).  I haven't added that
    here as it involves some API design.

    M ./compiler/basicTypes/DataCon.lhs -2 +12
    M ./compiler/typecheck/TcSplice.lhs -5 +22

I'm not particularly concerned about the specific API, but the following seems reasonable:

data Info
 ...
 | DataFamI Dec [DataFamInstance]
 | TypeFamI Dec [TypeFamInstance]
 ...

-- | Always a 'DataInstD' or 'NewtypeInstD' constructor
type DataFamInstance = Dec
-- | Always a 'TySynInstD' constructor
type TypeFamInstance = Dec

Alternatively, perhaps the DataFamI and TypeFamI constructors should be discarded in favour of a single FamI constructor.

Change History (8)

comment:1 Changed 3 years ago by simonpj

  • Cc alfonso.acosta@… illissius@… Ashley Yakeley SamAnklesaria added

Reasonable request -- but what should the API be? Currently for classes we have

classInstances :: Name -> [Type] -> Q [ClassInstance]
data Info = ClassI Dec ClassInstance | ...
data ClassInstance = ...a record of stuff about the instance...

So doing (reify c) gets you all the instance of class c in its ClassI; or you can look up an instance more selectively with classInstances (which returns all instances matching the type template).

Thoughts:

  • I like your idea of returning the instances as a Dec, rather than as a new data type like ClassInstance.
  • I'm slightly dubious about always returning all the instances of a class in its ClassI constructor; there could be a lot of them. But only slightly.

Here's a proposal

  • Generalise classInstances thus:
    reifyInstances :: Name -> [Type] -> Q [Dec]
    
    this would replace classInstances (or at least classInstances could be implemented in terms of it).
  • reifyInstances would work on a Name of a class, type family, or data family, returning a Dec that was a InstanceD, DataInstD, NewtypeInstD, or TySynInstD respectively.
  • For uniformity with ClassI, I suppose that TyConI should have a [Dec] that was the list of instances in the case of data or type families. But it's less nice, because most TyCons are not families, so the list would always be empty for them. I suppose we could split TyConI thus:
    data Info = ... | TyConI Dec
                    | FamilyConI Dec [Dec]
                ...
    
    where family type constructors come ot as FamilyTyConI.

I'm ccing other people who were involved in #1835.

Simon

comment:2 Changed 3 years ago by reinerp

What happens if the unfolding of a class instance is unavailable? For example:

module A where
  class C a where val :: a
  instance C Int where val = 0 -- suppose GHC doesn't expose this unfolding in A's interface file

module B where
  import A
  $( ...
     decs <- reifyInstances 'C ['Int] 
     ...
    )

The point is that the InstanceD constructor contains a list of values bound in the instance, including their RHSs. So what do we return if val's RHS is unavailable?

comment:3 Changed 3 years ago by simonpj

Sorry I should have been clearer. The Dec returned by reifyInstances would always

  • Be a suitable instance Dec, depending on the Name you are reifying (eg an InstanceD if you reify a class)
  • Have an empty list of sub-Decs. For a class, the [Dec] inside the InstanceD would be empty.

Using a Dec for this purpose is just convenience. One could invent a new data type specifically for instances -- but Dec is very convenient!

comment:4 Changed 3 years ago by simonpj

OK, I'm about to commit a patch implementing this change. Concering the last bullet of my proposal above, I decided to have a new constructor FamilyI in Info, partly because it's more explicit, and partly because it avoids requiring everyone who pattern-matches on TyConI to change their code.

Simon

comment:5 Changed 3 years ago by simonpj@…

commit 10c882760aea96a679a98bf76a603c1eeb99ecb8

Author: Simon Peyton Jones <simonpj@microsoft.com>
Date:   Tue Aug 23 13:46:43 2011 +0100

    Implement lookupTypeName/lookupValueName, and reification of type family instances
    
    This patch (and its TH counterpart) implements
       Trac #4429 (lookupTypeName, lookupValueName)
       Trac #5406 (reification of type/data family instances)
    
    See detailed discussion in those tickets.
    
    TH.ClassInstance is no more; instead reifyInstances returns a [Dec],
    which requires fewer data types and natuarally accommodates family
    instances.
    
    'reify' on a type/data family now returns 'FamilyI', a new data
    constructor in 'Info'

 compiler/typecheck/TcHsType.lhs |    2 +-
 compiler/typecheck/TcSplice.lhs |  163 ++++++++++++++++++++++++++++----------
 2 files changed, 121 insertions(+), 44 deletions(-)

comment:6 Changed 3 years ago by simonpj

  • Status changed from new to infoneeded

OK, done. reinerp: could you supply a regression test, please? Thanks.

Simon

comment:7 Changed 3 years ago by reinerp

Done. See #4429.

comment:8 Changed 3 years ago by simonpj

  • Resolution set to fixed
  • Status changed from infoneeded to closed
Note: See TracTickets for help on using tickets.