packages feed

th-compat 0.1.1 → 0.1.2

raw patch · 4 files changed

+187/−20 lines, 4 files

Files

CHANGELOG.md view
@@ -1,3 +1,8 @@+### 0.1.2 [2021.03.12]+* Add `bindSplice`, `bindSplice_`, `examineSplice`, `joinSplice`,+  `hoistSplice`, `liftSplice`, and `unTypeSplice` to+  `Language.Haskell.TH.Syntax.Compat`.+ ### 0.1.1 [2021.02.07] * Mark `Language.Haskell.TH.Syntax.Compat` as `Trustworthy`. 
src/Language/Haskell/TH/Syntax/Compat.hs view
@@ -57,7 +57,7 @@     -- ** The @IsCode@ class   , IsCode(..)     -- ** Limitations of @IsCode@-    -- $limitations+    -- $isCodeLimitations     -- ** Functions from @Language.Haskell.TH.Syntax@   , unsafeCodeCoerce   , liftCode@@ -70,8 +70,15 @@   -- * @Splice@   , Splice   , SpliceQ+  , bindSplice+  , bindSplice_+  , examineSplice+  , hoistSplice+  , joinSplice+  , liftSplice   , liftTypedFromUntypedSplice   , unsafeSpliceCoerce+  , unTypeSplice #endif   ) where @@ -450,9 +457,21 @@ -- One troublesome aspect of writing backwards-compatible code involving 'Code' -- is that GHC 9.0 changed the types of typed Template Haskell splices. Before, -- they were of type @'Q' ('TExp' a)@, but they are now of type @'Code' 'Q' a@.--- The 'IsCode' class can be used to paper over the difference between these--- two types. For more details, consult the Haddocks for 'IsCode'.+-- This modules provides two mechanisms for smoothing over the differences+-- between these two types: --+-- * The 'IsCode' class can be used to convert 'Code' or 'TExp' values to+--   'Code', and vice versa.+--+-- * The 'Splice' type synonym uses CPP so that @'Splice' q a@ is a synonym for+--   @'Code' q a@ on GHC 9.0 or later and @q ('TExp' a)@ on older versions of+--   GHC. This module also defines versions of 'Code'- and 'TExp'-related+--   combinators that work over 'Splice'.+--+-- Refer to the Haddocks for 'IsCode' and 'Splice' for more information on each+-- approach. Both approaches have pros and cons, and as a result, neither+-- approach is a one-size-fits-all solution.+-- -- Because 'Code' interacts with typed Template Haskell, the 'Code' type and -- any function that mentions 'Code' in its type are only defined on -- @template-haskell-2.9.0.0@ (GHC 7.8) or later.@@ -517,7 +536,7 @@   toCode   = liftCode   fromCode = examineCode --- $limitations+-- $isCodeLimitations -- 'IsCode' makes it possible to backport code involving typed Template Haskell -- quotations and splices where the types are monomorphized to 'Q'. GHC 9.0 -- and later, however, make it possible to use typed TH quotations and splices@@ -675,8 +694,7 @@ -- which version of @template-haskell@ you are using. It is mostly useful for -- contexts in which one is writing a definition that is intended to be used -- directly in a typed Template Haskell splice, as the types of TH splices--- differ between @template-haskell@ versions as well. One example of a type--- that uses 'Splice' is the type signature for 'lifTypedFromUntypedSplice'.+-- differ between @template-haskell@ versions as well. -- -- Levity-polymorphic since /template-haskell-2.16.0.0/. # if MIN_VERSION_template_haskell(2,17,0)@@ -708,6 +726,121 @@ type SpliceQ a = Splice Q a # endif +-- | A variant of 'bindCode' that works over 'Splice's. Because this function+-- uses 'Splice', the type of this function will be different depending on+-- which version of @template-haskell@ you are using. (See the Haddocks for+-- 'Splice' for more information on this point.)+--+-- Levity-polymorphic since /template-haskell-2.16.0.0/.+bindSplice ::+#  if MIN_VERSION_template_haskell(2,16,0)+  forall m a (r :: RuntimeRep) (b :: TYPE r) .+#  else+  forall m a b .+#  endif+  Monad m => m a -> (a -> Splice m b) -> Splice m b+# if MIN_VERSION_template_haskell(2,17,0)+bindSplice = bindCode+# else+bindSplice q k = liftSplice (q >>= examineSplice . k)+# endif++-- | A variant of 'bindCode_' that works over 'Splice's. Because this function+-- uses 'Splice', the type of this function will be different depending on+-- which version of @template-haskell@ you are using. (See the Haddocks for+-- 'Splice' for more information on this point.)+--+-- Levity-polymorphic since /template-haskell-2.16.0.0/.+bindSplice_ ::+#  if MIN_VERSION_template_haskell(2,16,0)+  forall m a (r :: RuntimeRep) (b :: TYPE r) .+#  else+  forall m a b .+#  endif+  Monad m => m a -> Splice m b -> Splice m b+# if MIN_VERSION_template_haskell(2,17,0)+bindSplice_ = bindCode_+# else+bindSplice_ q c = liftSplice ( q >> examineSplice c)+# endif++-- | A variant of 'examineCode' that takes a 'Splice' as an argument. Because+-- this function takes a 'Splice' as an argyment, the type of this function+-- will be different depending on which version of @template-haskell@ you are+-- using. (See the Haddocks for 'Splice' for more information on this point.)+--+-- Levity-polymorphic since /template-haskell-2.16.0.0/.+examineSplice ::+# if MIN_VERSION_template_haskell(2,16,0)+  forall (r :: RuntimeRep) m (a :: TYPE r) .+# else+  forall m a .+# endif+  Splice m a -> m (Syntax.TExp a)+# if MIN_VERSION_template_haskell(2,17,0)+examineSplice = examineCode+# else+examineSplice = id+# endif++-- | A variant of 'hoistCode' that works over 'Splice's. Because this function+-- uses 'Splice', the type of this function will be different depending on+-- which version of @template-haskell@ you are using. (See the Haddocks for+-- 'Splice' for more information on this point.)+--+-- Levity-polymorphic since /template-haskell-2.16.0.0/.+hoistSplice ::+#  if MIN_VERSION_template_haskell(2,16,0)+  forall m n (r :: RuntimeRep) (a :: TYPE r) .+#  else+  forall m n a .+#  endif+  Monad m => (forall x . m x -> n x) -> Splice m a -> Splice n a+# if MIN_VERSION_template_haskell(2,17,0)+hoistSplice = hoistCode+# else+hoistSplice f a = f a+# endif++-- | A variant of 'joinCode' that works over 'Splice's. Because this function+-- uses 'Splice', the type of this function will be different depending on+-- which version of @template-haskell@ you are using. (See the Haddocks for+-- 'Splice' for more information on this point.)+--+-- Levity-polymorphic since /template-haskell-2.16.0.0/.+joinSplice ::+#  if MIN_VERSION_template_haskell(2,16,0)+  forall m (r :: RuntimeRep) (a :: TYPE r) .+#  else+  forall m a .+#  endif+  Monad m => m (Splice m a) -> Splice m a+# if MIN_VERSION_template_haskell(2,17,0)+joinSplice = joinCode+# else+joinSplice = flip bindSplice id+# endif++-- | A variant of 'liftCode' that returns a 'Splice'. Because this function+-- returns a 'Splice', the return type of this function will be different+-- depending on which version of @template-haskell@ you are using. (See the+-- Haddocks for 'Splice' for more+-- information on this point.)+--+-- Levity-polymorphic since /template-haskell-2.16.0.0/.+liftSplice ::+# if MIN_VERSION_template_haskell(2,16,0)+  forall (r :: RuntimeRep) (a :: TYPE r) m .+# else+  forall a m .+# endif+  m (Syntax.TExp a) -> Splice m a+# if MIN_VERSION_template_haskell(2,17,0)+liftSplice = liftCode+# else+liftSplice = id+# endif+ -- | A variant of 'liftTypedQuote' that is: -- -- 1. Always implemented in terms of 'Syntax.lift' behind the scenes, and@@ -717,7 +850,7 @@ --    using. (See the Haddocks for 'Splice' for more information on this --    point.) ----- This is primarily useful for minimizing CPP in one particular scenario:+-- This is especially useful for minimizing CPP in one particular scenario: -- implementing 'Syntax.liftTyped' in hand-written 'Syntax.Lift' instances -- where the corresponding 'Syntax.lift' implementation cannot be derived. For -- instance, consider this example from the @text@ library:@@ -755,17 +888,13 @@ liftTypedFromUntypedSplice :: (Syntax.Lift t, Quote m) => t -> Splice m t liftTypedFromUntypedSplice = unsafeSpliceCoerce . liftQuote --- | Unsafely convert an untyped code representation into a typed code--- representation, where:------ * The splice representation is @'Code' m a@, if using---   @template-haskell-2.17.0.0@ or later, or------ * The splice representation is @m ('Syntax.TExp' a)@, if using an older---   version of @template-haskell@.+-- | Unsafely convert an untyped splice representation into a typed 'Splice'+-- representation. Because this function returns a 'Splice', the return type of+-- this function will be different depending on which version of+-- @template-haskell@ you are using. (See the Haddocks for 'Splice' for more+-- information on this point.) ----- This is primarily useful for minimizing CPP when the following two--- conditions are met:+-- This is especially useful for minimizing CPP when: -- -- 1. You need to implement 'Syntax.liftTyped' in a hand-written 'Syntax.Lift' --    instance where the corresponding 'Syntax.lift' implementation cannot be@@ -801,5 +930,24 @@ unsafeSpliceCoerce = unsafeCodeCoerce # else unsafeSpliceCoerce = unsafeTExpCoerceQuote+# endif++-- | A variant of 'unTypeCode' that takes a 'Splice' as an argument. Because+-- this function takes a 'Splice' as an argyment, the type of this function+-- will be different depending on which version of @template-haskell@ you are+-- using. (See the Haddocks for 'Splice' for more information on this point.)+--+-- Levity-polymorphic since /template-haskell-2.16.0.0/.+unTypeSplice ::+# if MIN_VERSION_template_haskell(2,16,0)+  forall (r :: RuntimeRep) (a :: TYPE r) m .+# else+  forall a m .+# endif+  Quote m => Splice m a -> m Exp+# if MIN_VERSION_template_haskell(2,17,0)+unTypeSplice = unTypeCode+# else+unTypeSplice = unTypeQQuote # endif #endif
tests/Language/Haskell/TH/Syntax/CompatSpec.hs view
@@ -43,9 +43,22 @@     it "manipulates typed TH expressions in a backwards-compatible way" $       $$(fromCode (toCode [|| "abc" ||])) `shouldBe` "abc" +  describe "joinSplice" $+    it "allows intermixing typed TH splices with monadic computations in a convenient way" $+      $$(joinSplice (do { x <- return "abc"; return [|| x ||] })) `shouldBe` "abc"++  describe "liftSplice" $+    it "allows intermixing typed TH splices with monadic computations in a convenient way" $+      $$(liftSplice (do { x <- return "abc"; examineSplice [|| x ||] })) `shouldBe` "abc"+   describe "liftTypedFromUntypedSplice" $     it "allows defining liftTyped in a convenient, backwards-compatible way" $       $$(liftTypedFromUntypedSplice MkFoo) `shouldBe` MkFoo++  describe "unTypeSplice" $+    it "allows unwrapping Code in a convenient, backwards-compatible way" $+      $$(unsafeSpliceCoerce (return . ListE =<< traverse unTypeSplice [ [|| "abc" ||] ]) :: SpliceQ [String])+        `shouldBe` ["abc"] #endif  newtype PureQ a = MkPureQ (State Uniq a)
th-compat.cabal view
@@ -1,6 +1,6 @@ cabal-version:       >=1.10 name:                th-compat-version:             0.1.1+version:             0.1.2 synopsis:            Backward- (and forward-)compatible Quote and Code types description:         This package defines a "Language.Haskell.TH.Syntax.Compat"                      module, which backports the @Quote@ and @Code@ types to@@ -29,8 +29,9 @@                    , GHC == 8.2.2                    , GHC == 8.4.4                    , GHC == 8.6.5-                   , GHC == 8.8.3-                   , GHC == 8.10.1+                   , GHC == 8.8.4+                   , GHC == 8.10.4+                   , GHC == 9.0.1 extra-source-files:  CHANGELOG.md, README.md  source-repository head