packages feed

bifunctors 5.4.2 → 5.5

raw patch · 6 files changed

+331/−484 lines, 6 filesdep +th-abstractionPVP ok

version bump matches the API change (PVP)

Dependencies added: th-abstraction

API changes (from Hackage documentation)

+ Data.Bifunctor.TH: Options :: Bool -> Options
+ Data.Bifunctor.TH: [emptyCaseBehavior] :: Options -> Bool
+ Data.Bifunctor.TH: defaultOptions :: Options
+ Data.Bifunctor.TH: deriveBifoldableOptions :: Options -> Name -> Q [Dec]
+ Data.Bifunctor.TH: deriveBifunctorOptions :: Options -> Name -> Q [Dec]
+ Data.Bifunctor.TH: deriveBitraversableOptions :: Options -> Name -> Q [Dec]
+ Data.Bifunctor.TH: instance GHC.Classes.Eq Data.Bifunctor.TH.Options
+ Data.Bifunctor.TH: instance GHC.Classes.Ord Data.Bifunctor.TH.Options
+ Data.Bifunctor.TH: instance GHC.Read.Read Data.Bifunctor.TH.Options
+ Data.Bifunctor.TH: instance GHC.Show.Show Data.Bifunctor.TH.Options
+ Data.Bifunctor.TH: makeBifoldMapOptions :: Options -> Name -> Q Exp
+ Data.Bifunctor.TH: makeBifoldOptions :: Options -> Name -> Q Exp
+ Data.Bifunctor.TH: makeBifoldlOptions :: Options -> Name -> Q Exp
+ Data.Bifunctor.TH: makeBifoldrOptions :: Options -> Name -> Q Exp
+ Data.Bifunctor.TH: makeBimapMOptions :: Options -> Name -> Q Exp
+ Data.Bifunctor.TH: makeBimapOptions :: Options -> Name -> Q Exp
+ Data.Bifunctor.TH: makeBisequenceAOptions :: Options -> Name -> Q Exp
+ Data.Bifunctor.TH: makeBisequenceOptions :: Options -> Name -> Q Exp
+ Data.Bifunctor.TH: makeBitraverseOptions :: Options -> Name -> Q Exp
+ Data.Bifunctor.TH: newtype Options

Files

.travis.yml view
@@ -34,9 +34,9 @@     - env: CABALVER=1.24 GHCVER=8.0.2       compiler: ": #GHC 8.0.2"       addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.2], sources: [hvr-ghc]}}-    - env: CABALVER=2.0 GHCVER=8.2.1-      compiler: ": #GHC 8.2.1"-      addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.1], sources: [hvr-ghc]}}+    - env: CABALVER=2.0 GHCVER=8.2.2+      compiler: ": #GHC 8.2.2"+      addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.2], sources: [hvr-ghc]}}     - env: CABALVER=head GHCVER=head       compiler: ": #GHC head"       addons: {apt: {packages: [cabal-install-head,ghc-head], sources: [hvr-ghc]}}
CHANGELOG.markdown view
@@ -1,3 +1,19 @@+5.5 [2017.12.07]+---+* `Data.Bifunctor.TH` now derives `bimap`/`bitraverse`+  implementations for empty data types that are strict in the argument.+* `Data.Bifunctor.TH` no longer derives `bifoldr`/`bifoldMap` implementations+  that error on empty data types. Instead, they simply return the folded state+  (for `bifoldr`) or `mempty` (for `bifoldMap`).+* When using `Data.Bifunctor.TH` to derive `Bifunctor` or `Bitraversable`+  instances for data types where the last two type variables are at phantom+  roles, generated `bimap`/`bitraverse` implementations now use `coerce` for+  efficiency.+* Add `Options` to `Data.Bifunctor.TH`, along with variants of existing+  functions that take `Options` as an argument. For now, the only configurable+  option is whether derived instances for empty data types should use the+  `EmptyCase` extension (this is disabled by default).+ 5.4.2 ----- * Make `deriveBitraversable` use `liftA2` in derived implementations of `bitraverse` when possible, now that `liftA2` is a class method of `Applicative` (as of GHC 8.2)
bifunctors.cabal view
@@ -1,6 +1,6 @@ name:          bifunctors category:      Data, Functors-version:       5.4.2+version:       5.5 license:       BSD3 cabal-version: >= 1.8 license-file:  LICENSE@@ -13,7 +13,7 @@ synopsis:      Bifunctors description:   Bifunctors build-type:    Simple-tested-with:   GHC == 7.0.4, GHC == 7.2.2, GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2+tested-with:   GHC == 7.0.4, GHC == 7.2.2, GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2 extra-source-files: .travis.yml CHANGELOG.markdown README.markdown  source-repository head@@ -44,6 +44,7 @@     comonad             >= 4     && < 6,     containers          >= 0.1   && < 0.6,     template-haskell    >= 2.4   && < 2.13,+    th-abstraction      >= 0.2.2 && < 0.3,     transformers        >= 0.2   && < 0.6,     transformers-compat >= 0.5   && < 0.6 
src/Data/Bifunctor/TH.hs view
@@ -31,32 +31,45 @@     -- $make     -- * 'Bifunctor'     deriveBifunctor+  , deriveBifunctorOptions   , makeBimap+  , makeBimapOptions     -- * 'Bifoldable'   , deriveBifoldable+  , deriveBifoldableOptions   , makeBifold+  , makeBifoldOptions   , makeBifoldMap+  , makeBifoldMapOptions   , makeBifoldr+  , makeBifoldrOptions   , makeBifoldl+  , makeBifoldlOptions     -- * 'Bitraversable'   , deriveBitraversable+  , deriveBitraversableOptions   , makeBitraverse+  , makeBitraverseOptions   , makeBisequenceA+  , makeBisequenceAOptions   , makeBimapM+  , makeBimapMOptions   , makeBisequence+  , makeBisequenceOptions+    -- * 'Options'+  , Options(..)+  , defaultOptions   ) where  import           Control.Monad (guard, unless, when, zipWithM)  import           Data.Bifunctor.TH.Internal import           Data.Either (rights)-#if MIN_VERSION_template_haskell(2,8,0) && !(MIN_VERSION_template_haskell(2,10,0))-import           Data.Foldable (foldr')-#endif import           Data.List import qualified Data.Map as Map (fromList, keys, lookup, size) import           Data.Maybe +import           Language.Haskell.TH.Datatype import           Language.Haskell.TH.Lib import           Language.Haskell.TH.Ppr import           Language.Haskell.TH.Syntax@@ -65,6 +78,22 @@ -- User-facing API ------------------------------------------------------------------------------- +-- | Options that further configure how the functions in "Data.Bifunctor.TH"+-- should behave.+newtype Options = Options+  { emptyCaseBehavior :: Bool+    -- ^ If 'True', derived instances for empty data types (i.e., ones with+    --   no data constructors) will use the @EmptyCase@ language extension.+    --   If 'False', derived instances will simply use 'seq' instead.+    --   (This has no effect on GHCs before 7.8, since @EmptyCase@ is only+    --   available in 7.8 or later.)+  } deriving (Eq, Ord, Read, Show)++-- | Conservative 'Options' that doesn't attempt to use @EmptyCase@ (to+-- prevent users from having to enable that extension at use sites.)+defaultOptions :: Options+defaultOptions = Options { emptyCaseBehavior = False }+ {- $derive  'deriveBifunctor', 'deriveBifoldable', and 'deriveBitraversable' automatically@@ -166,40 +195,68 @@ -- | Generates a 'Bifunctor' instance declaration for the given data type or data -- family instance. deriveBifunctor :: Name -> Q [Dec]-deriveBifunctor = deriveBiClass Bifunctor+deriveBifunctor = deriveBifunctorOptions defaultOptions +-- | Like 'deriveBifunctor', but takes an 'Options' argument.+deriveBifunctorOptions :: Options -> Name -> Q [Dec]+deriveBifunctorOptions = deriveBiClass Bifunctor+ -- | Generates a lambda expression which behaves like 'bimap' (without requiring a -- 'Bifunctor' instance). makeBimap :: Name -> Q Exp-makeBimap = makeBiFun Bimap+makeBimap = makeBimapOptions defaultOptions +-- | Like 'makeBimap', but takes an 'Options' argument.+makeBimapOptions :: Options -> Name -> Q Exp+makeBimapOptions = makeBiFun Bimap+ -- | Generates a 'Bifoldable' instance declaration for the given data type or data -- family instance. deriveBifoldable :: Name -> Q [Dec]-deriveBifoldable = deriveBiClass Bifoldable+deriveBifoldable = deriveBifoldableOptions defaultOptions --- | Generates a lambda expression which behaves like 'bifold' (without requiring a+-- | Like 'deriveBifoldable', but takes an 'Options' argument.+deriveBifoldableOptions :: Options -> Name -> Q [Dec]+deriveBifoldableOptions = deriveBiClass Bifoldable++--- | Generates a lambda expression which behaves like 'bifold' (without requiring a -- 'Bifoldable' instance). makeBifold :: Name -> Q Exp-makeBifold name = appsE [ makeBifoldMap name-                        , varE idValName-                        , varE idValName-                        ]+makeBifold = makeBifoldOptions defaultOptions --- | Generates a lambda expression which behaves like 'bifoldMap' (without requiring a--- 'Bifoldable' instance).+-- | Like 'makeBifold', but takes an 'Options' argument.+makeBifoldOptions :: Options -> Name -> Q Exp+makeBifoldOptions opts name = appsE [ makeBifoldMapOptions opts name+                                    , varE idValName+                                    , varE idValName+                                    ]++-- | Generates a lambda expression which behaves like 'bifoldMap' (without requiring+-- a 'Bifoldable' instance). makeBifoldMap :: Name -> Q Exp-makeBifoldMap = makeBiFun BifoldMap+makeBifoldMap = makeBifoldMapOptions defaultOptions +-- | Like 'makeBifoldMap', but takes an 'Options' argument.+makeBifoldMapOptions :: Options -> Name -> Q Exp+makeBifoldMapOptions = makeBiFun BifoldMap+ -- | Generates a lambda expression which behaves like 'bifoldr' (without requiring a -- 'Bifoldable' instance). makeBifoldr :: Name -> Q Exp-makeBifoldr = makeBiFun Bifoldr+makeBifoldr = makeBifoldrOptions defaultOptions +-- | Like 'makeBifoldr', but takes an 'Options' argument.+makeBifoldrOptions :: Options -> Name -> Q Exp+makeBifoldrOptions = makeBiFun Bifoldr+ -- | Generates a lambda expression which behaves like 'bifoldl' (without requiring a -- 'Bifoldable' instance). makeBifoldl :: Name -> Q Exp-makeBifoldl name = do+makeBifoldl = makeBifoldlOptions defaultOptions++-- | Like 'makeBifoldl', but takes an 'Options' argument.+makeBifoldlOptions :: Options -> Name -> Q Exp+makeBifoldlOptions opts name = do   f <- newName "f"   g <- newName "g"   z <- newName "z"@@ -207,7 +264,10 @@   lamE [varP f, varP g, varP z, varP t] $     appsE [ varE appEndoValName           , appsE [ varE getDualValName-                  , appsE [ makeBifoldMap name, foldFun f, foldFun g, varE t]+                  , appsE [ makeBifoldMapOptions opts name+                          , foldFun f+                          , foldFun g+                          , varE t]                   ]           , varE z           ]@@ -223,112 +283,195 @@ -- | Generates a 'Bitraversable' instance declaration for the given data type or data -- family instance. deriveBitraversable :: Name -> Q [Dec]-deriveBitraversable = deriveBiClass Bitraversable+deriveBitraversable = deriveBitraversableOptions defaultOptions --- | Generates a lambda expression which behaves like 'bitraverse' (without requiring a--- 'Bitraversable' instance).+-- | Like 'deriveBitraversable', but takes an 'Options' argument.+deriveBitraversableOptions :: Options -> Name -> Q [Dec]+deriveBitraversableOptions = deriveBiClass Bitraversable++-- | Generates a lambda expression which behaves like 'bitraverse' (without+-- requiring a 'Bitraversable' instance). makeBitraverse :: Name -> Q Exp-makeBitraverse = makeBiFun Bitraverse+makeBitraverse = makeBitraverseOptions defaultOptions --- | Generates a lambda expression which behaves like 'bisequenceA' (without requiring a--- 'Bitraversable' instance).+-- | Like 'makeBitraverse', but takes an 'Options' argument.+makeBitraverseOptions :: Options -> Name -> Q Exp+makeBitraverseOptions = makeBiFun Bitraverse++-- | Generates a lambda expression which behaves like 'bisequenceA' (without+-- requiring a 'Bitraversable' instance). makeBisequenceA :: Name -> Q Exp-makeBisequenceA name = appsE [ makeBitraverse name-                             , varE idValName-                             , varE idValName-                             ]+makeBisequenceA = makeBisequenceAOptions defaultOptions --- | Generates a lambda expression which behaves like 'bimapM' (without requiring a--- 'Bitraversable' instance).+-- | Like 'makeBitraverseA', but takes an 'Options' argument.+makeBisequenceAOptions :: Options -> Name -> Q Exp+makeBisequenceAOptions opts name = appsE [ makeBitraverseOptions opts name+                                         , varE idValName+                                         , varE idValName+                                         ]++-- | Generates a lambda expression which behaves like 'bimapM' (without+-- requiring a 'Bitraversable' instance). makeBimapM :: Name -> Q Exp-makeBimapM name = do+makeBimapM = makeBimapMOptions defaultOptions++-- | Like 'makeBimapM', but takes an 'Options' argument.+makeBimapMOptions :: Options -> Name -> Q Exp+makeBimapMOptions opts name = do   f <- newName "f"   g <- newName "g"   lamE [varP f, varP g] . infixApp (varE unwrapMonadValName) (varE composeValName) $-                          appsE [makeBitraverse name, wrapMonadExp f, wrapMonadExp g]+                          appsE [ makeBitraverseOptions opts name+                                , wrapMonadExp f+                                , wrapMonadExp g+                                ]   where     wrapMonadExp :: Name -> Q Exp     wrapMonadExp n = infixApp (conE wrapMonadDataName) (varE composeValName) (varE n) --- | Generates a lambda expression which behaves like 'bisequence' (without requiring a--- 'Bitraversable' instance).+-- | Generates a lambda expression which behaves like 'bisequence' (without+-- requiring a 'Bitraversable' instance). makeBisequence :: Name -> Q Exp-makeBisequence name = appsE [ makeBimapM name-                            , varE idValName-                            , varE idValName-                            ]+makeBisequence = makeBisequenceOptions defaultOptions +-- | Like 'makeBisequence', but takes an 'Options' argument.+makeBisequenceOptions :: Options -> Name -> Q Exp+makeBisequenceOptions opts name = appsE [ makeBimapMOptions opts name+                                        , varE idValName+                                        , varE idValName+                                        ]+ ------------------------------------------------------------------------------- -- Code generation -------------------------------------------------------------------------------  -- | Derive a class instance declaration (depending on the BiClass argument's value).-deriveBiClass :: BiClass -> Name -> Q [Dec]-deriveBiClass biClass name = withType name fromCons where-  fromCons :: Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q [Dec]-  fromCons name' ctxt tvbs cons mbTys = (:[]) `fmap` do-    (instanceCxt, instanceType)-        <- buildTypeInstance biClass name' ctxt tvbs mbTys-    instanceD (return instanceCxt)-              (return instanceType)-              (biFunDecs biClass cons)+deriveBiClass :: BiClass -> Options -> Name -> Q [Dec]+deriveBiClass biClass opts name = do+  info <- reifyDatatype name+  case info of+    DatatypeInfo { datatypeContext = ctxt+                 , datatypeName    = parentName+                 , datatypeVars    = vars+                 , datatypeVariant = variant+                 , datatypeCons    = cons+                 } -> do+      (instanceCxt, instanceType)+          <- buildTypeInstance biClass parentName ctxt vars variant+      (:[]) `fmap` instanceD (return instanceCxt)+                             (return instanceType)+                             (biFunDecs biClass opts parentName vars cons)  -- | Generates a declaration defining the primary function(s) corresponding to a -- particular class (bimap for Bifunctor, bifoldr and bifoldMap for Bifoldable, and -- bitraverse for Bitraversable). -- -- For why both bifoldr and bifoldMap are derived for Bifoldable, see Trac #7436.-biFunDecs :: BiClass -> [Con] -> [Q Dec]-biFunDecs biClass cons = map makeFunD $ biClassToFuns biClass where-  makeFunD :: BiFun -> Q Dec-  makeFunD biFun =-    funD (biFunName biFun)-         [ clause []-                  (normalB $ makeBiFunForCons biFun cons)-                  []-         ]+biFunDecs :: BiClass -> Options -> Name -> [Type] -> [ConstructorInfo] -> [Q Dec]+biFunDecs biClass opts parentName vars cons =+  map makeFunD $ biClassToFuns biClass+  where+    makeFunD :: BiFun -> Q Dec+    makeFunD biFun =+      funD (biFunName biFun)+           [ clause []+                    (normalB $ makeBiFunForCons biFun opts parentName vars cons)+                    []+           ]  -- | Generates a lambda expression which behaves like the BiFun argument.-makeBiFun :: BiFun -> Name -> Q Exp-makeBiFun biFun name = withType name fromCons where-  fromCons :: Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q Exp-  fromCons name' ctxt tvbs cons mbTys =-    -- We force buildTypeInstance here since it performs some checks for whether-    -- or not the provided datatype can actually have bimap/bifoldr/bitraverse/etc.-    -- implemented for it, and produces errors if it can't.-    buildTypeInstance (biFunToClass biFun) name' ctxt tvbs mbTys-      `seq` makeBiFunForCons biFun cons+makeBiFun :: BiFun -> Options -> Name -> Q Exp+makeBiFun biFun opts name = do+  info <- reifyDatatype name+  case info of+    DatatypeInfo { datatypeContext = ctxt+                 , datatypeName    = parentName+                 , datatypeVars    = vars+                 , datatypeVariant = variant+                 , datatypeCons    = cons+                 } ->+      -- We force buildTypeInstance here since it performs some checks for whether+      -- or not the provided datatype can actually have bimap/bifoldr/bitraverse/etc.+      -- implemented for it, and produces errors if it can't.+      buildTypeInstance (biFunToClass biFun) parentName ctxt vars variant+        >> makeBiFunForCons biFun opts parentName vars cons  -- | Generates a lambda expression for the given constructors. -- All constructors must be from the same type.-makeBiFunForCons :: BiFun -> [Con] -> Q Exp-makeBiFunForCons biFun cons = do+makeBiFunForCons :: BiFun -> Options -> Name -> [Type] -> [ConstructorInfo] -> Q Exp+makeBiFunForCons biFun opts _parentName vars cons = do   argNames <- mapM newName $ catMaybes [ Just "f"                                        , Just "g"                                        , guard (biFun == Bifoldr) >> Just "z"                                        , Just "value"                                        ]   let ([map1, map2], others) = splitAt 2 argNames-      z     = head others -- If we're deriving bifoldr, this will be well defined-                          -- and useful. Otherwise, it'll be ignored.-      value = last others+      z          = head others -- If we're deriving bifoldr, this will be well defined+                               -- and useful. Otherwise, it'll be ignored.+      value      = last others+      lastTyVars = map varTToName $ drop (length vars - 2) vars+      tvMap      = Map.fromList $ zip lastTyVars [map1, map2]   lamE (map varP argNames)       . appsE       $ [ varE $ biFunConstName biFun-        , if null cons-             then appE (varE errorValName)-                       (stringE $ "Void " ++ nameBase (biFunName biFun))-             else caseE (varE value)-                        (map (makeBiFunForCon biFun z map1 map2) cons)+        , makeFun z value tvMap         ] ++ map varE argNames+  where+    makeFun :: Name -> Name -> TyVarMap -> Q Exp+    makeFun z value tvMap = do+#if MIN_VERSION_template_haskell(2,9,0)+      roles <- reifyRoles _parentName+#endif+      case () of+        _ +#if MIN_VERSION_template_haskell(2,9,0)+          | Just (rs, PhantomR) <- unsnoc roles+          , Just (_,  PhantomR) <- unsnoc rs+         -> biFunPhantom z value+#endif++          | null cons && emptyCaseBehavior opts && ghc7'8OrLater+         -> biFunEmptyCase biFun z value++          | null cons+         -> biFunNoCons biFun z value++          | otherwise+         -> caseE (varE value)+                  (map (makeBiFunForCon biFun z tvMap) cons)++    ghc7'8OrLater :: Bool+#if __GLASGOW_HASKELL__ >= 708+    ghc7'8OrLater = True+#else+    ghc7'8OrLater = False+#endif++#if MIN_VERSION_template_haskell(2,9,0)+    biFunPhantom :: Name -> Name -> Q Exp+    biFunPhantom z value =+        biFunTrivial coerce+                     (varE pureValName `appE` coerce)+                     biFun z+      where+        coerce :: Q Exp+        coerce = varE coerceValName `appE` varE value+#endif+ -- | Generates a lambda expression for a single constructor.-makeBiFunForCon :: BiFun -> Name -> Name -> Name -> Con -> Q Match-makeBiFunForCon biFun z map1 map2 con = do-  let conName = constructorName con-  (ts, tvMap) <- reifyConTys biFun conName map1 map2-  argNames    <- newNameList "_arg" $ length ts-  makeBiFunForArgs biFun z tvMap conName ts argNames+makeBiFunForCon :: BiFun -> Name -> TyVarMap -> ConstructorInfo -> Q Match+makeBiFunForCon biFun z tvMap+  (ConstructorInfo { constructorName    = conName+                   , constructorContext = ctxt+                   , constructorFields  = ts }) = do+    ts'      <- mapM resolveTypeSynonyms ts+    argNames <- newNameList "_arg" $ length ts'+    if (any (`predMentionsName` Map.keys tvMap) ctxt+          || Map.size tvMap < 2)+          && not (allowExQuant (biFunToClass biFun))+       then existentialContextError conName+       else makeBiFunForArgs biFun z tvMap conName ts' argNames  -- | Generates a lambda expression for a single constructor's arguments. makeBiFunForArgs :: BiFun@@ -455,196 +598,27 @@ -- Template Haskell reifying and AST manipulation ------------------------------------------------------------------------------- --- | Boilerplate for top level splices.------ The given Name must meet one of two criteria:------ 1. It must be the name of a type constructor of a plain data type or newtype.--- 2. It must be the name of a data family instance or newtype instance constructor.------ Any other value will result in an exception.-withType :: Name-         -> (Name -> Cxt -> [TyVarBndr] -> [Con] -> Maybe [Type] -> Q a)-         -> Q a-withType name f = do-  info <- reify name-  case info of-    TyConI dec ->-      case dec of-        DataD ctxt _ tvbs-#if MIN_VERSION_template_haskell(2,11,0)-              _-#endif-              cons _ -> f name ctxt tvbs cons Nothing-        NewtypeD ctxt _ tvbs-#if MIN_VERSION_template_haskell(2,11,0)-                 _-#endif-                 con _ -> f name ctxt tvbs [con] Nothing-        _ -> error $ ns ++ "Unsupported type: " ++ show dec-#if MIN_VERSION_template_haskell(2,7,0)-# if MIN_VERSION_template_haskell(2,11,0)-    DataConI _ _ parentName   -> do-# else-    DataConI _ _ parentName _ -> do-# endif-      parentInfo <- reify parentName-      case parentInfo of-# if MIN_VERSION_template_haskell(2,11,0)-        FamilyI (DataFamilyD _ tvbs _) decs ->-# else-        FamilyI (FamilyD DataFam _ tvbs _) decs ->-# endif-          let instDec = flip find decs $ \dec -> case dec of-                DataInstD _ _ _-# if MIN_VERSION_template_haskell(2,11,0)-                          _-# endif-                          cons _ -> any ((name ==) . constructorName) cons-                NewtypeInstD _ _ _-# if MIN_VERSION_template_haskell(2,11,0)-                             _-# endif-                             con _ -> name == constructorName con-                _ -> error $ ns ++ "Must be a data or newtype instance."-           in case instDec of-                Just (DataInstD ctxt _ instTys-# if MIN_VERSION_template_haskell(2,11,0)-                                _-# endif-                                cons _)-                  -> f parentName ctxt tvbs cons $ Just instTys-                Just (NewtypeInstD ctxt _ instTys-# if MIN_VERSION_template_haskell(2,11,0)-                                   _-# endif-                                   con _)-                  -> f parentName ctxt tvbs [con] $ Just instTys-                _ -> error $ ns ++-                  "Could not find data or newtype instance constructor."-        _ -> error $ ns ++ "Data constructor " ++ show name ++-          " is not from a data family instance constructor."-# if MIN_VERSION_template_haskell(2,11,0)-    FamilyI DataFamilyD{} _ ->-# else-    FamilyI (FamilyD DataFam _ _ _) _ ->-# endif-      error $ ns ++-        "Cannot use a data family name. Use a data family instance constructor instead."-    _ -> error $ ns ++ "The name must be of a plain data type constructor, "-                    ++ "or a data family instance constructor."-#else-    DataConI{} -> dataConIError-    _          -> error $ ns ++ "The name must be of a plain type constructor."-#endif-  where-    ns :: String-    ns = "Data.Bifunctor.TH.withType: "---- | Deduces the instance context and head for an instance.+-- For the given Types, generate an instance context and head. Coming up with+-- the instance type isn't as simple as dropping the last types, as you need to+-- be wary of kinds being instantiated with *.+-- See Note [Type inference in derived instances] buildTypeInstance :: BiClass                   -- ^ Bifunctor, Bifoldable, or Bitraversable                   -> Name                   -- ^ The type constructor or data family name                   -> Cxt                   -- ^ The datatype context-                  -> [TyVarBndr]-                  -- ^ The type variables from the data type/data family declaration-                  -> Maybe [Type]-                  -- ^ 'Just' the types used to instantiate a data family instance,-                  -- or 'Nothing' if it's a plain data type+                  -> [Type]+                  -- ^ The types to instantiate the instance with+                  -> DatatypeVariant+                  -- ^ Are we dealing with a data family instance or not                   -> Q (Cxt, Type)--- Plain data type/newtype case-buildTypeInstance biClass tyConName dataCxt tvbs Nothing =-    let varTys :: [Type]-        varTys = map tvbToType tvbs-    in buildTypeInstanceFromTys biClass tyConName dataCxt varTys False--- Data family instance case------ The CPP is present to work around a couple of annoying old GHC bugs.--- See Note [Polykinded data families in Template Haskell]-buildTypeInstance biClass parentName dataCxt tvbs (Just instTysAndKinds) = do-#if !(MIN_VERSION_template_haskell(2,8,0)) || MIN_VERSION_template_haskell(2,10,0)-    let instTys :: [Type]-        instTys = zipWith stealKindForType tvbs instTysAndKinds-#else-    let kindVarNames :: [Name]-        kindVarNames = nub $ concatMap (tyVarNamesOfType . tvbKind) tvbs--        numKindVars :: Int-        numKindVars = length kindVarNames--        givenKinds, givenKinds' :: [Kind]-        givenTys                :: [Type]-        (givenKinds, givenTys) = splitAt numKindVars instTysAndKinds-        givenKinds' = map sanitizeStars givenKinds--        -- A GHC 7.6-specific bug requires us to replace all occurrences of-        -- (ConT GHC.Prim.*) with StarT, or else Template Haskell will reject it.-        -- Luckily, (ConT GHC.Prim.*) only seems to occur in this one spot.-        sanitizeStars :: Kind -> Kind-        sanitizeStars = go-          where-            go :: Kind -> Kind-            go (AppT t1 t2)                 = AppT (go t1) (go t2)-            go (SigT t k)                   = SigT (go t) (go k)-            go (ConT n) | n == starKindName = StarT-            go t                            = t--    -- If we run this code with GHC 7.8, we might have to generate extra type-    -- variables to compensate for any type variables that Template Haskell-    -- eta-reduced away.-    -- See Note [Polykinded data families in Template Haskell]-    xTypeNames <- newNameList "tExtra" (length tvbs - length givenTys)--    let xTys   :: [Type]-        xTys = map VarT xTypeNames-        -- ^ Because these type variables were eta-reduced away, we can only-        --   determine their kind by using stealKindForType. Therefore, we mark-        --   them as VarT to ensure they will be given an explicit kind annotation-        --   (and so the kind inference machinery has the right information).--        substNamesWithKinds :: [(Name, Kind)] -> Type -> Type-        substNamesWithKinds nks t = foldr' (uncurry substNameWithKind) t nks--        -- The types from the data family instance might not have explicit kind-        -- annotations, which the kind machinery needs to work correctly. To-        -- compensate, we use stealKindForType to explicitly annotate any-        -- types without kind annotations.-        instTys :: [Type]-        instTys = map (substNamesWithKinds (zip kindVarNames givenKinds'))-                  -- Note that due to a GHC 7.8-specific bug-                  -- (see Note [Polykinded data families in Template Haskell]),-                  -- there may be more kind variable names than there are kinds-                  -- to substitute. But this is OK! If a kind is eta-reduced, it-                  -- means that is was not instantiated to something more specific,-                  --   so we need not substitute it. Using stealKindForType will-                  --   grab the correct kind.-                $ zipWith stealKindForType tvbs (givenTys ++ xTys)-#endif-    buildTypeInstanceFromTys biClass parentName dataCxt instTys True---- For the given Types, generate an instance context and head. Coming up with--- the instance type isn't as simple as dropping the last types, as you need to--- be wary of kinds being instantiated with *.--- See Note [Type inference in derived instances]-buildTypeInstanceFromTys :: BiClass-                         -- ^ Bifunctor, Bifoldable, or Bitraversable-                         -> Name-                         -- ^ The type constructor or data family name-                         -> Cxt-                         -- ^ The datatype context-                         -> [Type]-                         -- ^ The types to instantiate the instance with-                         -> Bool-                         -- ^ True if it's a data family, False otherwise-                         -> Q (Cxt, Type)-buildTypeInstanceFromTys biClass tyConName dataCxt varTysOrig isDataFamily = do+buildTypeInstance biClass tyConName dataCxt varTysOrig variant = do     -- Make sure to expand through type/kind synonyms! Otherwise, the     -- eta-reduction check might get tripped up over type variables in a     -- synonym that are actually dropped.     -- (See GHC Trac #11416 for a scenario where this actually happened.)-    varTysExp <- mapM expandSyn varTysOrig+    varTysExp <- mapM resolveTypeSynonyms varTysOrig      let remainingLength :: Int         remainingLength = length varTysOrig - 2@@ -674,7 +648,7 @@         -- All of the type variables mentioned in the dropped types         -- (post-synonym expansion)         droppedTyVarNames :: [Name]-        droppedTyVarNames = concatMap tyVarNamesOfType droppedTysExpSubst+        droppedTyVarNames = freeVariables droppedTysExpSubst      -- If any of the dropped types were polykinded, ensure that they are of kind *     -- after substituting * for the dropped kind variables. If not, throw an error.@@ -715,6 +689,13 @@           map (substNamesWithKindStar (union droppedKindVarNames kvNames'))             $ take remainingLength varTysOrig +        isDataFamily :: Bool+        isDataFamily = case variant of+                         Datatype        -> False+                         Newtype         -> False+                         DataInstance    -> True+                         NewtypeInstance -> True+         remainingTysOrigSubst' :: [Type]         -- See Note [Kind signatures in derived instances] for an explanation         -- of the isDataFamily check.@@ -759,55 +740,6 @@     tName = varTToName t  {--Note [Polykinded data families in Template Haskell]-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--In order to come up with the correct instance context and head for an instance, e.g.,--  instance C a => C (Data a) where ...--We need to know the exact types and kinds used to instantiate the instance. For-plain old datatypes, this is simple: every type must be a type variable, and-Template Haskell reliably tells us the type variables and their kinds.--Doing the same for data families proves to be much harder for three reasons:--1. On any version of Template Haskell, it may not tell you what an instantiated-   type's kind is. For instance, in the following data family instance:--     data family Fam (f :: * -> *) (a :: *)-     data instance Fam f a--   Then if we use TH's reify function, it would tell us the TyVarBndrs of the-   data family declaration are:--     [KindedTV f (AppT (AppT ArrowT StarT) StarT),KindedTV a StarT]--   and the instantiated types of the data family instance are:--     [VarT f1,VarT a1]--   We can't just pass [VarT f1,VarT a1] to buildTypeInstanceFromTys, since we-   have no way of knowing their kinds. Luckily, the TyVarBndrs tell us what the-   kind is in case an instantiated type isn't a SigT, so we use the stealKindForType-   function to ensure all of the instantiated types are SigTs before passing them-   to buildTypeInstanceFromTys.-2. On GHC 7.6 and 7.8, a bug is present in which Template Haskell lists all of-   the specified kinds of a data family instance efore any of the instantiated-   types. Fortunately, this is easy to deal with: you simply count the number of-   distinct kind variables in the data family declaration, take that many elements-   from the front of the  Types list of the data family instance, substitute the-   kind variables with their respective instantiated kinds (which you took earlier),-   and proceed as normal.-3. On GHC 7.8, an even uglier bug is present (GHC Trac #9692) in which Template-   Haskell might not even list all of the Types of a data family instance, since-   they are eta-reduced away! And yes, kinds can be eta-reduced too.--   The simplest workaround is to count how many instantiated types are missing from-   the list and generate extra type variables to use in their place. Luckily, we-   needn't worry much if its kind was eta-reduced away, since using stealKindForType-   will get it back.- Note [Kind signatures in derived instances] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -883,49 +815,6 @@         kind substitution as in the other case. -} --- Determines the types of a constructor's arguments as well as the last type--- parameters (along with their map functions), expanding through any type synonyms.--- The type parameters are determined on a constructor-by-constructor basis since--- they may be refined to be particular types in a GADT.-reifyConTys :: BiFun-            -> Name-            -> Name-            -> Name-            -> Q ([Type], TyVarMap)-reifyConTys biFun conName map1 map2 = do-    info          <- reify conName-    (ctxt, uncTy) <- case info of-        DataConI _ ty _-#if !(MIN_VERSION_template_haskell(2,11,0))-                 _-#endif-                 -> fmap uncurryTy (expandSyn ty)-        _ -> error "Must be a data constructor"-    let (argTys, [resTy]) = splitAt (length uncTy - 1) uncTy-        unapResTy = unapplyTy resTy-        -- If one of the last type variables is refined to a particular type-        -- (i.e., not truly polymorphic), we mark it with Nothing and filter-        -- it out later, since we only apply map functions to arguments of-        -- a type that it (1) one of the last type variables, and (2)-        -- of a truly polymorphic type.-        mbTvNames = map varTToName_maybe $-                        drop (length unapResTy - 2) unapResTy-        -- We use Map.fromList to ensure that if there are any duplicate type-        -- variables (as can happen in a GADT), the rightmost type variable gets-        -- associated with the map function.-        ---        -- See Note [Matching functions with GADT type variables]-        tvMap = Map.fromList-                    . catMaybes -- Drop refined types-                    $ zipWith (\mbTvName sp ->-                                  fmap (\tvName -> (tvName, sp)) mbTvName)-                              mbTvNames [map1, map2]-    if (any (`predMentionsName` Map.keys tvMap) ctxt-         || Map.size tvMap < 2)-         && not (allowExQuant (biFunToClass biFun))-       then existentialContextError conName-       else return (argTys, tvMap)- {- Note [Matching functions with GADT type variables] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~@@ -1025,17 +914,6 @@   "Cannot eta-reduce to an instance of form \n\tinstance (...) => "   ++ pprint instanceType -#if !(MIN_VERSION_template_haskell(2,7,0))--- | Template Haskell didn't list all of a data family's instances upon reification--- until template-haskell-2.7.0.0, which is necessary for a derived instance to work.-dataConIError :: a-dataConIError = error-  . showString "Cannot use a data constructor."-  . showString "\n\t(Note: if you are trying to derive for a data family instance,"-  . showString "\n\tuse GHC >= 7.4 instead.)"-  $ ""-#endif- ------------------------------------------------------------------------------- -- Class-specific constants -------------------------------------------------------------------------------@@ -1195,6 +1073,35 @@           (VarE liftA2ValName `AppE` conExp `AppE` e1 `AppE` e2) es      return . go . rights $ ess++biFunEmptyCase :: BiFun -> Name -> Name -> Q Exp+biFunEmptyCase biFun z value =+    biFunTrivial emptyCase+                 (varE pureValName `appE` emptyCase)+                 biFun z+  where+    emptyCase :: Q Exp+    emptyCase = caseE (varE value) []++biFunNoCons :: BiFun -> Name -> Name -> Q Exp+biFunNoCons biFun z value =+    biFunTrivial seqAndError+                 (varE pureValName `appE` seqAndError)+                 biFun z+  where+    seqAndError :: Q Exp+    seqAndError = appE (varE seqValName) (varE value) `appE`+                  appE (varE errorValName)+                        (stringE $ "Void " ++ nameBase (biFunName biFun))++biFunTrivial :: Q Exp -> Q Exp -> BiFun -> Name -> Q Exp+biFunTrivial bimapE bitraverseE biFun z = go biFun+  where+    go :: BiFun -> Q Exp+    go Bimap      = bimapE+    go Bifoldr    = varE z+    go BifoldMap  = varE memptyValName+    go Bitraverse = bitraverseE  {- Note [biFunTriv for Bifoldable and Bitraversable]
src/Data/Bifunctor/TH/Internal.hs view
@@ -15,17 +15,16 @@ -} module Data.Bifunctor.TH.Internal where -import           Control.Monad (liftM)- import           Data.Bifunctor (bimap) import           Data.Foldable (foldr') import           Data.List-import qualified Data.Map as Map (fromList, findWithDefault, singleton)+import qualified Data.Map as Map (singleton) import           Data.Map (Map) import           Data.Maybe (fromMaybe, mapMaybe) import qualified Data.Set as Set import           Data.Set (Set) +import           Language.Haskell.TH.Datatype import           Language.Haskell.TH.Lib import           Language.Haskell.TH.Syntax @@ -43,73 +42,15 @@ -- Expanding type synonyms ------------------------------------------------------------------------------- --- | Expands all type synonyms in a type. Written by Dan Rosén in the--- @genifunctors@ package (licensed under BSD3).-expandSyn :: Type -> Q Type-expandSyn (ForallT tvs ctx t) = fmap (ForallT tvs ctx) $ expandSyn t-expandSyn t@AppT{}            = expandSynApp t []-expandSyn t@ConT{}            = expandSynApp t []-expandSyn (SigT t k)          = do t' <- expandSyn t-                                   k' <- expandSynKind k-                                   return (SigT t' k')-expandSyn t                   = return t--expandSynKind :: Kind -> Q Kind-#if MIN_VERSION_template_haskell(2,8,0)-expandSynKind = expandSyn-#else-expandSynKind = return -- There are no kind synonyms to deal with-#endif--expandSynApp :: Type -> [Type] -> Q Type-expandSynApp (AppT t1 t2) ts = do-    t2' <- expandSyn t2-    expandSynApp t1 (t2':ts)-expandSynApp (ConT n) ts | nameBase n == "[]" = return $ foldl' AppT ListT ts-expandSynApp t@(ConT n) ts = do-    info <- reify n-    case info of-        TyConI (TySynD _ tvs rhs) ->-            let (ts', ts'') = splitAt (length tvs) ts-                subs = mkSubst tvs ts'-                rhs' = substType subs rhs-             in expandSynApp rhs' ts''-        _ -> return $ foldl' AppT t ts-expandSynApp t ts = do-    t' <- expandSyn t-    return $ foldl' AppT t' ts--type TypeSubst = Map Name Type-type KindSubst = Map Name Kind--mkSubst :: [TyVarBndr] -> [Type] -> TypeSubst-mkSubst vs ts =-   let vs' = map un vs-       un (PlainTV v)    = v-       un (KindedTV v _) = v-   in Map.fromList $ zip vs' ts--substType :: TypeSubst -> Type -> Type-substType subs (ForallT v c t) = ForallT v c $ substType subs t-substType subs t@(VarT n)      = Map.findWithDefault t n subs-substType subs (AppT t1 t2)    = AppT (substType subs t1) (substType subs t2)-substType subs (SigT t k)      = SigT (substType subs t)-#if MIN_VERSION_template_haskell(2,8,0)-                                      (substType subs k)-#else-                                      k-#endif-substType _ t                  = t--substKind :: KindSubst -> Type -> Type+applySubstitutionKind :: Map Name Kind -> Type -> Type #if MIN_VERSION_template_haskell(2,8,0)-substKind = substType+applySubstitutionKind = applySubstitution #else-substKind _ = id -- There are no kind variables!+applySubstitutionKind _ t = t #endif  substNameWithKind :: Name -> Kind -> Type -> Type-substNameWithKind n k = substKind (Map.singleton n k)+substNameWithKind n k = applySubstitutionKind (Map.singleton n k)  substNamesWithKindStar :: [Name] -> Type -> Type substNamesWithKindStar ns t = foldr' (flip substNameWithKind starK) t ns@@ -254,27 +195,6 @@ #endif isStarOrVar _      = False --- | Gets all of the type/kind variable names mentioned somewhere in a Type.-tyVarNamesOfType :: Type -> [Name]-tyVarNamesOfType = go-  where-    go :: Type -> [Name]-    go (AppT t1 t2) = go t1 ++ go t2-    go (SigT t _k)  = go t-#if MIN_VERSION_template_haskell(2,8,0)-                           ++ go _k-#endif-    go (VarT n)     = [n]-    go _            = []---- | Gets all of the type/kind variable names mentioned somewhere in a Kind.-tyVarNamesOfKind :: Kind -> [Name]-#if MIN_VERSION_template_haskell(2,8,0)-tyVarNamesOfKind = tyVarNamesOfType-#else-tyVarNamesOfKind _ = [] -- There are no kind variables-#endif- -- | @hasKindVarChain n kind@ Checks if @kind@ is of the form -- k_0 -> k_1 -> ... -> k_(n-1), where k0, k1, ..., and k_(n-1) can be * or -- kind variables.@@ -282,7 +202,7 @@ hasKindVarChain kindArrows t =   let uk = uncurryKind (tyKind t)   in if (length uk - 1 == kindArrows) && all isStarOrVar uk-        then Just (concatMap tyVarNamesOfKind uk)+        then Just (freeVariables uk)         else Nothing  -- | If a Type is a SigT, returns its kind signature. Otherwise, return *.@@ -290,15 +210,6 @@ tyKind (SigT _ k) = k tyKind _          = starK --- | If a VarT is missing an explicit kind signature, steal it from a TyVarBndr.-stealKindForType :: TyVarBndr -> Type -> Type-stealKindForType tvb t@VarT{} = SigT t (tvbKind tvb)-stealKindForType _   t        = t---- | Monadic version of concatMap-concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]-concatMapM f xs = liftM concat (mapM f xs)- -- | A mapping of type variable Names to their map function Names. For example, in a -- Bifunctor declaration, a TyVarMap might look like (a ~> f, b ~> g), where -- a and b are the last two type variables of the datatype, and f and g are the two@@ -308,31 +219,16 @@ thd3 :: (a, b, c) -> c thd3 (_, _, c) = c --- | Extracts the name of a constructor.-constructorName :: Con -> Name-constructorName (NormalC name      _  ) = name-constructorName (RecC    name      _  ) = name-constructorName (InfixC  _    name _  ) = name-constructorName (ForallC _    _    con) = constructorName con-#if MIN_VERSION_template_haskell(2,11,0)-constructorName (GadtC    names _ _)    = head names-constructorName (RecGadtC names _ _)    = head names-#endif+unsnoc :: [a] -> Maybe ([a], a)+unsnoc []     = Nothing+unsnoc (x:xs) = case unsnoc xs of+                  Nothing    -> Just ([], x)+                  Just (a,b) -> Just (x:a, b)  -- | Generate a list of fresh names with a common prefix, and numbered suffixes. newNameList :: String -> Int -> Q [Name] newNameList prefix n = mapM (newName . (prefix ++) . show) [1..n] --- | Extracts the kind from a TyVarBndr.-tvbKind :: TyVarBndr -> Kind-tvbKind (PlainTV  _)   = starK-tvbKind (KindedTV _ k) = k---- | Convert a TyVarBndr to a Type.-tvbToType :: TyVarBndr -> Type-tvbToType (PlainTV n)    = VarT n-tvbToType (KindedTV n k) = SigT (VarT n) k- -- | Applies a typeclass constraint to a type. applyClass :: Name -> Name -> Pred #if MIN_VERSION_template_haskell(2,10,0)@@ -520,6 +416,9 @@ bifoldMapConstValName :: Name bifoldMapConstValName = mkBifunctorsName_v "Data.Bifunctor.TH.Internal" "bifoldMapConst" +coerceValName :: Name+coerceValName = mkNameG_v "ghc-prim" "GHC.Prim" "coerce"+ bitraverseConstValName :: Name bitraverseConstValName = mkBifunctorsName_v "Data.Bifunctor.TH.Internal" "bitraverseConst" @@ -567,6 +466,9 @@  getDualValName :: Name getDualValName = mkNameG_v "base" "Data.Monoid" "getDual"++seqValName :: Name+seqValName = mkNameG_v "ghc-prim" "GHC.Prim" "seq"  traverseValName :: Name traverseValName = mkNameG_v "base" "Data.Traversable" "traverse"
tests/BifunctorSpec.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-}@@ -8,6 +9,11 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}+#if __GLASGOW_HASKELL__ >= 708+{-# LANGUAGE EmptyCase #-}+{-# LANGUAGE RoleAnnotations #-}+#endif+ {-# OPTIONS_GHC -fno-warn-name-shadowing #-} {-# OPTIONS_GHC -fno-warn-unused-matches #-} #if __GLASGOW_HASKELL__ >= 800@@ -105,6 +111,12 @@ data IntHashFun a b     = IntHashFun ((((a -> Int#) -> b) -> Int#) -> a) +data Empty1 a b+data Empty2 a b+#if __GLASGOW_HASKELL__ >= 708+type role Empty2 nominal nominal+#endif+ -- Data families  data family   StrangeFam x  y z@@ -207,6 +219,15 @@ $(deriveBitraversable ''IntHash)  $(deriveBifunctor     ''IntHashFun)++$(deriveBifunctor     ''Empty1)+$(deriveBifoldable    ''Empty1)+$(deriveBitraversable ''Empty1)++-- Use EmptyCase here+$(deriveBifunctorOptions     defaultOptions{emptyCaseBehavior = True} ''Empty2)+$(deriveBifoldableOptions    defaultOptions{emptyCaseBehavior = True} ''Empty2)+$(deriveBitraversableOptions defaultOptions{emptyCaseBehavior = True} ''Empty2)  #if MIN_VERSION_template_haskell(2,7,0) -- Data families