-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | Recurseively reify template haskell datatype info
--   
--   <tt>th-reify-many</tt> provides functions for recursively reifying top
--   level declarations. The main intended use case is for enumerating the
--   names of datatypes reachable from an initial datatype, and passing
--   these names to some function which generates instances.
@package th-reify-many
@version 0.1.6

module Language.Haskell.TH.ReifyMany.Internal

-- | Returns <a>True</a> if the <a>Dec</a> is a <a>DataD</a> or
--   <a>NewtypeD</a>
isDataDec :: Dec -> Bool

-- | Returns <a>True</a> if the <a>Dec</a> is a <a>DataD</a>,
--   <a>NewtypeD</a>, or <a>TySynD</a>.
isNormalTyCon :: Dec -> Bool

-- | For data, newtype, and type declarations, yields a list of the types
--   of the fields. In the case of a type synonyms, it just returns the
--   body of the type synonym as a singleton list.
decToFieldTypes :: Dec -> [[Type]]

-- | Returns the types of the fields of the constructor.
conToFieldTypes :: Con -> [Type]

-- | Returns the names of all type constructors which aren't involved in
--   constraints.
typeConcreteNames :: Type -> [Name]

-- | Returns the names of all type constructors used when defining type
--   constructors.
decConcreteNames :: Dec -> [Name]

-- | Datatype to capture the fields of <a>InstanceD</a>.
data TypeclassInstance
TypeclassInstance :: Cxt -> Type -> [Dec] -> TypeclassInstance

-- | Given the <a>Name</a> of a class, yield all of the
--   <a>TypeclassInstance</a>s, with synonyms expanded in the <a>Type</a>
--   field.
getInstances :: Name -> Q [TypeclassInstance]

-- | Returns the first <a>TypeclassInstance</a> where
--   <a>instanceMatches</a> returns true.
lookupInstance :: [TypeclassInstance] -> Name -> Maybe TypeclassInstance

-- | Checks if the given name is the head of one of the paramaters of the
--   given <a>TypeclassInstance</a>.
instanceMatches :: TypeclassInstance -> Name -> Bool

-- | Breaks a type application like <tt>A b c</tt> into [A, b, c].
unAppsT :: Type -> [Type]
instance GHC.Show.Show Language.Haskell.TH.ReifyMany.Internal.TypeclassInstance


-- | <tt>th-reify-many</tt> provides functions for recursively reifying top
--   level declarations. The main intended use case is for enumerating the
--   names of datatypes reachable from an initial datatype, and passing
--   these names to some function which generates instances.
--   
--   For example, in order to define <a>Lift</a> instances for two mutually
--   recursive datatypes, I could write something like:
--   
--   <pre>
--   {-# LANGUAGE TemplateHaskell #-}
--   import Language.Haskell.TH.ReifyMany (reifyManyWithoutInstances)
--   import Language.Haskell.TH.Lift (Lift(..), deriveLiftMany)
--   
--   data A = A B
--   
--   data B = B Int
--   
--   $(reifyManyWithoutInstances ''Lift [''A] (const True) &gt;&gt;= deriveLiftMany)
--   </pre>
--   
--   One interesting feature of this is that it attempts to omit the types
--   which already have an instance defined. For example, if
--   <tt>$(deriveLift ''B)</tt> is used before <tt>deriveLiftMany</tt>, it
--   will omit the instance for B.
--   
--   Of course, the intended usecase for this involves many more datatypes
--   - for example, syntax trees such as those found in TH.
--   
--   Note that <a>reifyManyWithoutInstances</a> is rather imperfect in its
--   testing of whether an instance exists, and whether an instance should
--   exist. See this function's docs for details.
module Language.Haskell.TH.ReifyMany

-- | Recursively enumerates type constructor declarations, halting when
--   datatypes appear to already have an instance for the typeclass
--   specified by the first <a>Name</a> parameter. It guesses that an
--   instance exists for a given datatype if it's used in the top
--   constructor of any of its parameters (see <a>instanceMatches</a>).
--   
--   This function is useful for bulk defining typeclass instances like
--   <tt>Binary</tt>, <tt>Lift</tt>, <tt>Data</tt>, <tt>Typeable</tt>, etc.
--   It isn't very clever, though - in particular it has the following
--   limitations:
--   
--   <ul>
--   <li>It only works well when type constructors mentioned in fields
--   should all have instances defined for them.</li>
--   <li>It ignores data type / constructor constraints.</li>
--   <li>It ignores data / type families.</li>
--   </ul>
--   
--   It also takes a user-defined predicate, which is useful in situations
--   where this attempts to descend into datatypes which do not need
--   instances defined for them.
--   
--   Note that this will always initially yield the <a>Name</a>s of the
--   initial types, regardless of whether they are instances or not.
reifyManyWithoutInstances :: Name -> [Name] -> (Name -> Bool) -> Q [Name]

-- | Like <a>reifyMany</a>, but specialized for recursively enumerating
--   type constructor declarations, omitting <a>PrimTyConI</a>.
--   
--   In order to have this behave like <a>reifyManyWithoutInstances</a>,
--   but not do any instance filtering, use it with the <a>isDataDec</a>
--   and <a>decConcreteNames</a> internal utilities. For example:
--   
--   <pre>
--   {-# LANGUAGE TemplateHaskell #-}
--   import Language.Haskell.TH
--   import Language.Haskell.TH.ReifyMany
--   import Language.Haskell.TH.ReifyMany.Internal
--   
--   $(do results &lt;- reifyManyTyCons
--            (\(_, dec) -&gt; return (isDataDec dec, decConcreteNames dec))
--            [''Exp]
--        -- Display the results
--        reportError (show (map fst results))
--        -- This TH splice doesn't generate any code.
--        return []
--    )
--   </pre>
reifyManyTyCons :: ((Name, Dec) -> Q (Bool, [Name])) -> [Name] -> Q [(Name, Info)]

-- | Starting from a set of initial top level declarations, specified by
--   <tt>[Name]</tt>, recursively enumerate other related declarations. The
--   provided function determines whether the current info be included in
--   the list of results, and which <a>Name</a>s to lookup next. This
--   function handles keeping track of which <a>Name</a>s have already been
--   visited.
reifyMany :: ((Name, Info) -> Q (Bool, [Name])) -> [Name] -> Q [(Name, Info)]
