unbound-generics 0.4.2 → 0.4.3
raw patch · 14 files changed
+263/−60 lines, 14 filesdep ~transformers
Dependency ranges changed: transformers
Files
- Changelog.md +12/−1
- README.md +5/−5
- examples/F.hs +21/−12
- examples/LC.hs +2/−2
- src/Unbound/Generics/LocallyNameless/Alpha.hs +2/−0
- src/Unbound/Generics/LocallyNameless/Fresh.hs +4/−0
- src/Unbound/Generics/LocallyNameless/LFresh.hs +8/−0
- src/Unbound/Generics/LocallyNameless/Rec.hs +1/−1
- src/Unbound/Generics/LocallyNameless/Subst.hs +66/−14
- test/AlphaProperties.hs +27/−0
- test/PropOpenClose.hs +1/−16
- test/TestSubstBind.hs +102/−0
- test/test-main.hs +2/−0
- unbound-generics.cabal +10/−9
Changelog.md view
@@ -1,5 +1,16 @@ # NEXT +# 0.4.3++* Add an `instantiate` function that substitutes a list of terms for a collection of bound variables in a toplevel `Bind p t` term.+ Thanks to Stephanie Weirich (sweirich). This adds a new `substBvs` function to the `Subst` class.+* Add `substBind` operation that substitutes for the bound variable of a `Bind (Name a) t` term.+ This is a specialization of `instantiate` to the case where the pattern is a single `Name a`+* Tests for `substBind` by Mark Lemay (marklemay) Thanks!+* Expose `Rec` constructor of the `Rec` type and the `ctxLevel` function from `AlphaCtx`+* Require `transformers < 0.6`, run CI with GHC 9.4, drop CI with GHC 7.10.+ Thanks to Andreas Abel (andreaasabel).+ # 0.4.2 * Add `Functor` instance for `Unbound.Generics.LocallyNameless.Internal.Iso.Exchange`@@ -117,7 +128,7 @@ * Tested with GHC 8.2.2 * Compile with `-Wcompat` * Add `Semigroup` instances for all types that were previously `Monoid` instances-* Added more examples to the [examples/ directory](https://github.com/lambdageek/unbound-generics/tree/master/examples)+* Added more examples to the [examples/ directory](https://github.com/lambdageek/unbound-generics/tree/main/examples) * Added "exceptions" dependency and `MonadThrow`, `MonadCatch`, `MonadMask` instances for `FreshMT` and `LFreshMT`. Thanks Alex McKenna.
README.md view
@@ -4,7 +4,7 @@ [](https://discord.gg/CRfu93W) [](https://hackage.haskell.org/package/unbound-generics)-[](https://github.com/lambdageek/unbound-generics/actions?query=workflow%3ACI+branch%3Amaster)+[](https://github.com/lambdageek/unbound-generics/actions?query=workflow%3ACI+branch%3Amain) <!-- [](https://travis-ci.org/lambdageek/unbound-generics) --> Support for programming with names and binders using GHC Generics.@@ -50,18 +50,18 @@ -- evaluation takes an expression and returns a value while using a source of fresh names eval :: Expr -> FreshM Expr-eval (V x) = fail $ "unbound variable " ++ show x-eval e@(Lam {}) = return e+eval (V x) = error $ "unbound variable " ++ show x+eval e@Lam{} = return e eval (App e1 e2) = do v1 <- eval e1 v2 <- eval e2 case v1 of- (Lam bnd) -> do+ Lam bnd -> do -- open the lambda by picking a fresh name for the bound variable x in body (x, body) <- unbind bnd let body' = subst x v2 body eval body'- _ -> fail "application of non-lambda"+ _ -> error "application of non-lambda" example :: Expr example =
examples/F.hs view
@@ -26,14 +26,14 @@ data Ty = TyVar TyName | Arr Ty Ty- | All (Bind TyName Ty)+ | All (Bind [TyName] Ty) deriving (Show, Generic, Typeable) data Tm = TmVar TmName | Lam (Bind (TmName, Embed Ty) Tm)- | TLam (Bind TyName Tm)+ | TLam (Bind [TyName] Tm) | App Tm Tm- | TApp Tm Ty+ | TApp Tm [Ty] deriving (Show, Generic, Typeable) ------------------------------------------------------@@ -65,21 +65,31 @@ -- /\a. \x:a. x polyid :: Tm-polyid = TLam (bind a (Lam (bind (x, Embed (TyVar a)) (TmVar x))))+polyid = TLam (bind [a] (Lam (bind (x, Embed (TyVar a)) (TmVar x)))) -- All a. a -> a polyidty :: Ty-polyidty = All (bind a (Arr (TyVar a) (TyVar a)))+polyidty = All (bind [a] (Arr (TyVar a) (TyVar a))) -- /\b. \y:b. y polyid2 :: Tm-polyid2 = TLam (bind b (Lam (bind (y, Embed (TyVar b)) (TmVar y))))+polyid2 = TLam (bind [b] (Lam (bind (y, Embed (TyVar b)) (TmVar y)))) -- /\c. \y:b. y bad_polyid2 :: Tm-bad_polyid2 = TLam (bind c (Lam (bind (y, Embed (TyVar b)) (TmVar y))))+bad_polyid2 = TLam (bind [c] (Lam (bind (y, Embed (TyVar b)) (TmVar y)))) +-- /\a b. a -> b -> a+const_ty :: Ty+const_ty = All (bind [a,b] (Arr (TyVar a) (Arr (TyVar b) (TyVar a)))) +-- /\a b. a -> b -> a+const_tm :: Tm+const_tm = TLam (bind [a,b] (Lam (bind (x, Embed (TyVar a)) (Lam (bind (y, Embed (TyVar b)) (TmVar x))))))++test :: Ty+test = fst (runM (ti emptyCtx (TApp const_tm [polyidty, All (bind [c] (TyVar c))])))+ ----------------------------------------------------------------- -- Typechecker -----------------------------------------------------------------@@ -112,8 +122,8 @@ Just s -> return s Nothing -> throwError "NotFound" -extendTy :: TyName -> Ctx -> Ctx-extendTy n ctx = ctx { getDelta = n : (getDelta ctx) }+extendTy :: [TyName] -> Ctx -> Ctx+extendTy ns ctx = ctx { getDelta = ns <> (getDelta ctx) } extendTm :: TmName -> Ty -> Ctx -> Ctx extendTm n ty ctx = ctx { getGamma = (n, ty) : (getGamma ctx) }@@ -162,9 +172,8 @@ tyt <- ti g t case tyt of (All bnder) -> do- tcty g ty- (n1, ty1) <- unbind bnder- return $ subst n1 ty ty1+ mapM_ (tcty g) ty+ return $ instantiate bnder ty _ -> throwError $ "Expected a ForAll in a type application, got " ++ show tyt
examples/LC.hs view
@@ -48,8 +48,7 @@ e2' <- red e2 case e1' of Lam bnd -> do- (x, e1'') <- unbind bnd- return $ subst x e2' e1''+ return $ substBind bnd e2' otherwise -> return $ App e1' e2' red (Lam bnd) = do (x, e) <- unbind bnd@@ -105,3 +104,4 @@ assertM "be3" $ if_ true (Var x) (Var y) =~ Var x assertM "be4" $ if_ false (Var x) (Var y) =~ Var y assertM "be5" $ App (App plus one) two =~ three+ print "Done"
src/Unbound/Generics/LocallyNameless/Alpha.hs view
@@ -25,6 +25,7 @@ , NthPatFind(..) , NamePatFind(..) , AlphaCtx+ , ctxLevel , initialCtx , patternCtx , termCtx@@ -32,6 +33,7 @@ , incrLevelCtx , decrLevelCtx , isZeroLevelCtx+ , ctxLevel -- * Internal , gaeq , gfvAny
src/Unbound/Generics/LocallyNameless/Fresh.hs view
@@ -30,7 +30,9 @@ #endif import Control.Monad.Trans import Control.Monad.Trans.Except+#if !MIN_VERSION_transformers(0,6,0) import Control.Monad.Trans.Error+#endif import Control.Monad.Trans.Maybe import Control.Monad.Trans.Reader import Control.Monad.Trans.State.Lazy as Lazy@@ -119,8 +121,10 @@ return $ (Fn s n) fresh nm@(Bn {}) = return nm +#if !MIN_VERSION_transformers(0,6,0) instance (Error e, Fresh m) => Fresh (ErrorT e m) where fresh = lift . fresh+#endif instance Fresh m => Fresh (ExceptT e m) where fresh = lift . fresh
src/Unbound/Generics/LocallyNameless/LFresh.hs view
@@ -77,10 +77,14 @@ import Control.Applicative (Applicative, Alternative) import Control.Monad.Trans.Cont+#if !MIN_VERSION_transformers(0,6,0) import Control.Monad.Trans.Error+#endif import Control.Monad.Trans.Except import Control.Monad.Trans.Identity+#if !MIN_VERSION_transformers(0,6,0) import Control.Monad.Trans.List+#endif import Control.Monad.Trans.Maybe import Control.Monad.Trans.State.Lazy as Lazy import Control.Monad.Trans.State.Strict as Strict@@ -164,10 +168,12 @@ avoid = mapContT . avoid getAvoids = lift getAvoids +#if !MIN_VERSION_transformers(0,6,0) instance (Error e, LFresh m) => LFresh (ErrorT e m) where lfresh = lift . lfresh avoid = mapErrorT . avoid getAvoids = lift getAvoids+#endif instance LFresh m => LFresh (ExceptT e m) where lfresh = lift . lfresh@@ -179,10 +185,12 @@ avoid = mapIdentityT . avoid getAvoids = lift getAvoids +#if !MIN_VERSION_transformers(0,6,0) instance LFresh m => LFresh (ListT m) where lfresh = lift . lfresh avoid = mapListT . avoid getAvoids = lift getAvoids+#endif instance LFresh m => LFresh (MaybeT m) where lfresh = lift . lfresh
src/Unbound/Generics/LocallyNameless/Rec.hs view
@@ -13,7 +13,7 @@ {-# LANGUAGE DeriveGeneric #-} module Unbound.Generics.LocallyNameless.Rec (- Rec+ Rec (Rec) , rec , unrec , TRec (..)
src/Unbound/Generics/LocallyNameless/Subst.hs view
@@ -46,6 +46,8 @@ SubstName(..) , SubstCoerce(..) , Subst(..)+ , substBind+ , instantiate ) where import GHC.Generics@@ -69,6 +71,18 @@ data SubstCoerce a b where SubstCoerce :: Name b -> (b -> Maybe a) -> SubstCoerce a b +-- | Immediately substitute for the bound variables of a pattern+-- in a binder, without first naming the variables.+-- NOTE: this operation does not check that the number of terms passed in+-- match the number of variables in the pattern. (Or that they are of appropriate type.)+instantiate :: (Alpha a, Alpha b, Alpha p , Subst a b) => Bind p b -> [a] -> b+instantiate bnd u = instantiate_ bnd u++-- | A version of 'instantiate' with a more general type+instantiate_ :: Subst a b => Bind p b -> [a] -> b+instantiate_ (B _p t) u = substBvs initialCtx u t++ -- | Instances of @'Subst' b a@ are terms of type @a@ that may contain -- variables of type @b@ that may participate in capture-avoiding -- substitution.@@ -109,31 +123,48 @@ | otherwise = error $ "Cannot substitute for bound variable in: " ++ show (map fst ss) + -- Bound variable substitution (replace a single pattern variable with a list of terms)+ -- Similar to open, but replaces with b's instead of with names+ -- Does not check whether enough b's are provided: will ignore extra if there are too many+ -- and skip the substitution if there are too few.+ substBvs :: AlphaCtx -> [b] -> a -> a+ default substBvs :: (Generic a, GSubst b (Rep a)) => AlphaCtx -> [b] -> a -> a+ substBvs ctx bs x =+ case (isvar x :: Maybe (SubstName a b)) of+ Just (SubstName (Bn j k)) | ctxLevel ctx == j, fromInteger k < length bs -> bs !! fromInteger k+ _ -> to $ gsubstBvs ctx bs (from x)+ ---- generic structural substitution. class GSubst b f where gsubst :: Name b -> b -> f c -> f c gsubsts :: [(Name b, b)] -> f c -> f c+ gsubstBvs :: AlphaCtx -> [b] -> f c -> f c instance Subst b c => GSubst b (K1 i c) where gsubst nm val = K1 . subst nm val . unK1 gsubsts ss = K1 . substs ss . unK1+ gsubstBvs ctx b = K1 . substBvs ctx b . unK1 instance GSubst b f => GSubst b (M1 i c f) where gsubst nm val = M1 . gsubst nm val . unM1 gsubsts ss = M1 . gsubsts ss . unM1+ gsubstBvs c b = M1 . gsubstBvs c b . unM1 instance GSubst b U1 where gsubst _nm _val _ = U1 gsubsts _ss _ = U1+ gsubstBvs _c _b _ = U1 instance GSubst b V1 where gsubst _nm _val = id gsubsts _ss = id+ gsubstBvs _c _b = id instance (GSubst b f, GSubst b g) => GSubst b (f :*: g) where gsubst nm val (f :*: g) = gsubst nm val f :*: gsubst nm val g gsubsts ss (f :*: g) = gsubsts ss f :*: gsubsts ss g+ gsubstBvs c b (f :*: g) = gsubstBvs c b f :*: gsubstBvs c b g instance (GSubst b f, GSubst b g) => GSubst b (f :+: g) where gsubst nm val (L1 f) = L1 $ gsubst nm val f@@ -142,18 +173,21 @@ gsubsts ss (L1 f) = L1 $ gsubsts ss f gsubsts ss (R1 g) = R1 $ gsubsts ss g + gsubstBvs c b (L1 f) = L1 $ gsubstBvs c b f+ gsubstBvs c b (R1 g) = R1 $ gsubstBvs c b g+ -- these have a Generic instance, but -- it's self-refential (ie: Rep Int = D1 (C1 (S1 (Rec0 Int)))) -- so our structural GSubst instances get stuck in an infinite loop.-instance Subst b Int where subst _ _ = id ; substs _ = id-instance Subst b Bool where subst _ _ = id ; substs _ = id-instance Subst b () where subst _ _ = id ; substs _ = id-instance Subst b Char where subst _ _ = id ; substs _ = id-instance Subst b Float where subst _ _ = id ; substs _ = id-instance Subst b Double where subst _ _ = id ; substs _ = id+instance Subst b Int where subst _ _ = id ; substs _ = id ; substBvs _ _ = id+instance Subst b Bool where subst _ _ = id ; substs _ = id ; substBvs _ _ = id+instance Subst b () where subst _ _ = id ; substs _ = id ; substBvs _ _ = id+instance Subst b Char where subst _ _ = id ; substs _ = id ; substBvs _ _ = id+instance Subst b Float where subst _ _ = id ; substs _ = id ; substBvs _ _ = id+instance Subst b Double where subst _ _ = id ; substs _ = id ; substBvs _ _ = id -- huh, apparently there's no instance Generic Integer. -instance Subst b Integer where subst _ _ = id ; substs _ = id+instance Subst b Integer where subst _ _ = id ; substs _ = id ; substBvs _ _ = id instance (Subst c a, Subst c b) => Subst c (a,b) instance (Subst c a, Subst c b, Subst c d) => Subst c (a,b,d)@@ -164,23 +198,41 @@ instance (Subst c a) => Subst c (Maybe a) instance (Subst c a, Subst c b) => Subst c (Either a b) -instance Subst b (Name a) where subst _ _ = id ; substs _ = id-instance Subst b AnyName where subst _ _ = id ; substs _ = id+instance Subst b (Name a) where subst _ _ = id ; substs _ = id ; substBvs _ _ = id+instance Subst b AnyName where subst _ _ = id ; substs _ = id ; substBvs _ _ = id -instance (Subst c a) => Subst c (Embed a)+instance (Subst c a) => Subst c (Embed a) where+ substBvs c us (Embed x)+ | isTermCtx c = Embed (substBvs (termCtx c) us x)+ | otherwise = error "Internal error: substBvs on Embed" instance (Subst c e) => Subst c (Shift e) where subst x b (Shift e) = Shift (subst x b e) substs ss (Shift e) = Shift (substs ss e)+ substBvs c b (Shift e) = Shift (substBvs (decrLevelCtx c) b e) -instance (Subst c b, Subst c a, Alpha a, Alpha b) => Subst c (Bind a b)+instance (Subst c b, Subst c a, Alpha a, Alpha b) => Subst c (Bind a b) where+ substBvs c b (B p t) = B (substBvs (patternCtx c) b p) (substBvs (incrLevelCtx c) b t) -instance (Subst c p1, Subst c p2) => Subst c (Rebind p1 p2)+instance (Subst c p1, Subst c p2) => Subst c (Rebind p1 p2) where+ substBvs c us (Rebnd p q) = Rebnd (substBvs c us p) (substBvs (incrLevelCtx c) us q) -instance (Subst c p) => Subst c (Rec p)+instance (Subst c p) => Subst c (Rec p) where+ substBvs c us (Rec p) = Rec (substBvs (incrLevelCtx c) us p) -instance (Alpha p, Subst c p) => Subst c (TRec p)+instance (Alpha p, Subst c p) => Subst c (TRec p) where+ substBvs c us (TRec p) = TRec (substBvs (patternCtx (incrLevelCtx c)) us p) instance Subst a (Ignore b) where subst _ _ = id substs _ = id+ substBvs _ _ = id++-- | Specialized version of capture-avoiding substitution for that operates on a @'Bind' ('Name' a) t@ term to @'unbind'@+-- the bound name @Name a@ and immediately subsitute a new term for its occurrences.+--+-- This is a specialization of @'instantiate' :: Bind pat term -> [a] -> term@ where the @'Bind' pat term@ has a pattern that is just+-- a single @'Name' a@ and there is a single substitution term of type @a@. Unlike 'instantiate', this function cannot fail at runtime.+substBind :: Subst a t => Bind (Name a) t -> a -> t+substBind b u = instantiate_ b [u]+
+ test/AlphaProperties.hs view
@@ -0,0 +1,27 @@+module AlphaProperties where + +import Unbound.Generics.LocallyNameless (fv, aeq, Name, Alpha) + +import Test.Tasty.QuickCheck (counterexample, Property, testProperty) + +import Data.Typeable (Typeable) + +import Data.Monoid (Any(..)) +import Unbound.Generics.LocallyNameless.Internal.Fold (foldMapOf, toListOf) + + + +isFreeIn :: (Typeable a, Alpha b) => Name a -> b -> Bool +isFreeIn = elementOf fv + where + elementOf l = anyOf l . (==) + anyOf l f = getAny . foldMapOf l (Any . f) + +notFreeIn :: (Typeable a, Alpha b) => Name a -> b -> Bool +notFreeIn v = not . isFreeIn v + +(=~=) :: (Alpha a, Show a) => a -> a -> Property +x =~= y = counterexample (show x ++ " not alpha equivalent to " ++ show y) (x `aeq` y) + +(/~@) :: (Typeable a, Alpha b, Show b) => Name a -> b -> Property +v /~@ t = counterexample (show v ++ " is free in " ++ show t) (v `notFreeIn` t)
test/PropOpenClose.hs view
@@ -13,23 +13,8 @@ import Unbound.Generics.LocallyNameless import Unbound.Generics.LocallyNameless.Internal.Fold (foldMapOf, toListOf) -------------------------------------------- Property testing utilities--isFreeIn :: (Typeable a, Alpha b) => Name a -> b -> Bool-isFreeIn = elementOf fv- where- elementOf l = anyOf l . (==)- anyOf l f = getAny . foldMapOf l (Any . f)--notFreeIn :: (Typeable a, Alpha b) => Name a -> b -> Bool-notFreeIn v = not . isFreeIn v--(=~=) :: (Alpha a, Show a) => a -> a -> Property-x =~= y = counterexample (show x ++ " not alpha equivalent to " ++ show y) (x `aeq` y)+import AlphaProperties -(/~@) :: (Typeable a, Alpha b, Show b) => Name a -> b -> Property-v /~@ t = counterexample (show v ++ " is free in " ++ show t) (v `notFreeIn` t) -- Wrapper around 'Name a' that has an Arbitrary instance that generates free names. -- Note that this doesn't guarantee /freshness/. The name may clash with some other one.
+ test/TestSubstBind.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE MultiParamTypeClasses, DeriveGeneric, DeriveDataTypeable #-} + +module TestSubstBind where + +import Test.Tasty +import Unbound.Generics.LocallyNameless +import Data.Typeable (Typeable) +import GHC.Generics (Generic) + + +import Test.QuickCheck +import Test.Tasty.QuickCheck (testProperty) +import Unbound.Generics.LocallyNameless.Unsafe (unsafeUnbind) + +import AlphaProperties + +type Var = Name Expr + +data Expr = V Var | Lam (Bind Var Expr) | I Int | App Expr Expr + deriving (Generic, Typeable, Show) + +instance Alpha Expr + +instance Subst Expr Expr where + isvar (V x) = Just (SubstName x) + isvar _ = Nothing + + +instance Arbitrary Expr where + arbitrary = sized arbitrarySizedExpr + + shrink (I i) = I <$> shrink i + shrink (Lam bndExp) = + (substBind bndExp <$> [I 0, V x, V y, V z]) -- does the problem persist with the binder removed? + ++ (Lam <$> underBinder shrink bndExp) -- shrink under the binder + shrink (f `App` a) = [f, a] ++ (App <$> shrink f <*> shrink a) + shrink _ = [] + +underBinder :: (Monad m) => (Expr -> m Expr) -> Bind Var Expr -> m (Bind Var Expr) +underBinder op bndExp = let + (name, bod) = unsafeUnbind bndExp -- Should be safe since no freshnames are invoked + in do + bod' <- op bod + pure $ bind name bod' + +arbitrarySizedExpr :: Int -> Gen Expr +arbitrarySizedExpr i | i < 1 = do + n <- arbitrary + var <- elements [x,y,z] + elements [I n, V $ var] +arbitrarySizedExpr i = do + rest <- arbitrarySizedExpr (i - 1) + var <- elements [x,y,z] + n <- arbitrary + f <- arbitrarySizedExpr (i `div` 2) -- TODO: reorganize better + a <- arbitrarySizedExpr (i `div` 2) + elements [Lam $ bind var rest, f `App` a, I n, V $ var] + + +x,y,z :: Var +x = s2n "x" +y = s2n "y" +z = s2n "z" + + +smallStep :: Expr -> Maybe Expr +smallStep ((Lam bndBod) `App` a) = Just $ substBind bndBod a +smallStep (f `App` a) = + case (smallStep f, smallStep a) of + (Nothing, Nothing) -> Nothing + (Just f', _) -> Just $ f' `App` a + (Nothing, Just a') -> Just $ f `App` a' +smallStep (Lam bndBod) = Lam <$> underBinder smallStep bndBod +smallStep _ = Nothing -- no step + + +smallStep' :: (Fresh m) => Expr -> m (Maybe Expr) +smallStep' ((Lam bndBod) `App` a) = do + (name, bod) <- unbind bndBod + pure $ Just $ subst name a bod +smallStep' (f `App` a) = do + mf' <- smallStep' f + ma' <- smallStep' a + case (mf', ma') of + (Nothing, Nothing) -> pure $ Nothing + (Just f', _) -> pure $ Just $ f' `App` a + (Nothing, Just a') -> pure $ Just $ f `App` a' +smallStep' (Lam bndBod) = do + (name, bod) <- unbind bndBod + mbod' <- smallStep' bod + case mbod' of + Nothing -> pure $ Nothing + Just bod' -> pure $ Just $ Lam $ bind name bod' +smallStep' _ = pure $ Nothing -- no step + + +expbindProp :: Expr -> Property +expbindProp e = smallStep e =~= runFreshM (smallStep' e) + +test_substBind :: TestTree +test_substBind = testGroup "substBind" + [testProperty "substBind matches unbind subst" $ expbindProp]
test/test-main.hs view
@@ -11,6 +11,7 @@ import TestIgnore import TestShiftEmbed import TestTH+import TestSubstBind main :: IO () main = defaultMain $ testGroup "unboundGenerics"@@ -24,4 +25,5 @@ , test_acompare , test_shiftEmbed , test_TH+ , test_substBind ]
unbound-generics.cabal view
@@ -1,8 +1,6 @@--- Initial unbound-generics.cabal generated by cabal init. For further --- documentation, see http://haskell.org/cabal/users-guide/-+cabal-version: >=1.10 name: unbound-generics-version: 0.4.2+version: 0.4.3 synopsis: Support for programming with names and binders using GHC Generics description: Specify the binding structure of your data type with an expressive set of type combinators, and unbound-generics@@ -15,7 +13,7 @@ but using <https://hackage.haskell.org/package/base/docs/GHC-Generics.html GHC.Generics> instead of <http://hackage.haskell.org/package/RepLib RepLib>. See the accompanying README for some porting notes.- + homepage: http://github.com/lambdageek/unbound-generics bug-reports: http://github.com/lambdageek/unbound-generics/issues license: BSD3@@ -25,12 +23,13 @@ copyright: (c) 2014-2022, Aleksey Kliger category: Language build-type: Simple+ extra-source-files: examples/*.hs, examples/*.lhs, README.md, Changelog.md-cabal-version: >=1.10-tested-with: GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.3, GHC == 8.10.*, GHC == 9.0.*, GHC == 9.2.*- ++tested-with: GHC == 7.8.4, GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.7, GHC == 9.0.2, GHC == 9.2.*, GHC == 9.4.*+ library exposed-modules: Unbound.Generics.LocallyNameless Unbound.Generics.LocallyNameless.Name@@ -57,7 +56,7 @@ template-haskell >= 2.8.0.0, deepseq >= 1.3.0.0, mtl >= 2.1,- transformers >= 0.3,+ transformers >= 0.3 && < 0.7, transformers-compat >= 0.3, containers >= 0.5 && < 0.7, contravariant >= 0.5,@@ -87,6 +86,8 @@ TestACompare TestShiftEmbed TestTH+ TestSubstBind+ AlphaProperties build-depends: base, mtl, tasty,