packages feed

vinyl 0.13.0 → 0.13.1

raw patch · 9 files changed

+348/−139 lines, 9 filesdep +constraintsdep +deepseqdep +singletons-thdep ~singletons

Dependencies added: constraints, deepseq, singletons-th

Dependency ranges changed: singletons

Files

CHANGELOG.md view
@@ -1,3 +1,6 @@+# 0.13.1+- GHC 9.0.1 support+ # 0.13.0 - GHC 8.10.1 support fix. A fix for the previous attempt at 8.10 support involves a backwards incompatible change. 
Data/Vinyl/ARec.hs view
@@ -1,133 +1,21 @@-{-# LANGUAGE AllowAmbiguousTypes #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE Trustworthy #-}+ -- | Constant-time field accessors for extensible records. The -- trade-off is the usual lists vs arrays one: it is fast to add an -- element to the head of a list, but element access is linear time; -- array access time is uniform, but extending the array is more -- slower.-module Data.Vinyl.ARec where-import Data.Vinyl.Core-import Data.Vinyl.Lens (RecElem(..), RecSubset(..))-import Data.Vinyl.TypeLevel--import qualified Data.Array as Array-import qualified Data.Array.Base as BArray-import GHC.Exts (Any)-import Unsafe.Coerce---- | An array-backed extensible record with constant-time field--- access.-newtype ARec (f :: k -> *) (ts :: [k]) = ARec (Array.Array Int Any)---- | Convert a 'Rec' into an 'ARec' for constant-time field access.-toARec :: forall f ts. (NatToInt (RLength ts)) => Rec f ts -> ARec f ts-toARec = go id-  where go :: ([Any] -> [Any]) -> Rec f ts' -> ARec f ts-        go acc RNil = ARec $! Array.listArray (0, n - 1) (acc [])-        go acc (x :& xs) = go (acc . (unsafeCoerce x :)) xs-        n = natToInt @(RLength ts)-{-# INLINE toARec #-}---- | Defines a constraint that lets us index into an 'ARec' in order--- to produce a 'Rec' using 'fromARec'.-class (NatToInt (RIndex t ts)) => IndexableField ts t where-instance (NatToInt (RIndex t ts)) => IndexableField ts t where---- | Convert an 'ARec' into a 'Rec'.-fromARec :: forall f ts.-            (RecApplicative ts, RPureConstrained (IndexableField ts) ts)-         => ARec f ts -> Rec f ts-fromARec (ARec arr) = rpureConstrained @(IndexableField ts) aux-  where aux :: forall t. NatToInt (RIndex t ts) => f t-        aux = unsafeCoerce (arr Array.! natToInt @(RIndex t ts))-{-# INLINE fromARec #-}---- | Get a field from an 'ARec'.-aget :: forall t f ts. (NatToInt (RIndex t ts)) => ARec f ts -> f t-aget (ARec arr) =-  unsafeCoerce (BArray.unsafeAt arr (natToInt @(RIndex t ts)))-{-# INLINE aget #-}---- | Set a field in an 'ARec'.-aput :: forall t t' f ts ts'. (NatToInt (RIndex t ts))-      => f t' -> ARec f ts -> ARec f ts'-aput x (ARec arr) = ARec (arr Array.// [(i, unsafeCoerce x)])-  where i = natToInt @(RIndex t ts)-{-# INLINE aput #-}---- | Define a lens for a field of an 'ARec'.-alens :: forall f g t t' ts ts'. (Functor g, NatToInt (RIndex t ts))-      => (f t -> g (f t')) -> ARec f ts -> g (ARec f ts')-alens f ar = fmap (flip (aput @t) ar) (f (aget ar))-{-# INLINE alens #-}---- instance (i ~ RIndex t ts, i ~ RIndex t' ts', NatToInt (RIndex t ts)) => RecElem ARec t t' ts ts' i where---   rlens = alens---   rget = aget---   rput = aput--instance RecElem ARec t t' (t ': ts) (t' ': ts) 'Z where-  rlensC = alens-  {-# INLINE rlensC #-}-  rgetC = aget-  {-# INLINE rgetC #-}-  rputC = aput @t-  {-# INLINE rputC #-}--instance (RIndex t (s ': ts) ~ 'S i, NatToInt i,  RecElem ARec t t' ts ts' i)-  => RecElem ARec t t' (s ': ts) (s ': ts') ('S i) where-  rlensC = alens-  {-# INLINE rlensC #-}-  rgetC = aget-  {-# INLINE rgetC #-}-  rputC = aput @t-  {-# INLINE rputC #-}---- | Get a subset of a record's fields.-arecGetSubset :: forall rs ss f.-                 (IndexWitnesses (RImage rs ss), NatToInt (RLength rs))-              => ARec f ss -> ARec f rs-arecGetSubset (ARec arr) = ARec (Array.listArray (0, n-1) $-                                 go (indexWitnesses @(RImage rs ss)))-  where go :: [Int] -> [Any]-        go = map (arr Array.!)-        n = natToInt @(RLength rs)-{-# INLINE arecGetSubset #-}---- | Set a subset of a larger record's fields to all of the fields of--- a smaller record.-arecSetSubset :: forall rs ss f. (IndexWitnesses (RImage rs ss))-              => ARec f ss -> ARec f rs -> ARec f ss-arecSetSubset (ARec arrBig) (ARec arrSmall) = ARec (arrBig Array.// updates)-  where updates = zip (indexWitnesses @(RImage rs ss)) (Array.elems arrSmall)-{-# INLINE arecSetSubset #-}--instance (is ~ RImage rs ss, IndexWitnesses is, NatToInt (RLength rs))-         => RecSubset ARec rs ss is where-  rsubsetC f big = fmap (arecSetSubset big) (f (arecGetSubset big))-  {-# INLINE rsubsetC #-}--instance (RPureConstrained (IndexableField rs) rs,-          RecApplicative rs,-          Show (Rec f rs)) => Show (ARec f rs) where-  show = show . fromARec--instance (RPureConstrained (IndexableField rs) rs,-          RecApplicative rs,-          Eq (Rec f rs)) => Eq (ARec f rs) where-  x == y = fromARec x == fromARec y--instance (RPureConstrained (IndexableField rs) rs,-          RecApplicative rs,-          Ord (Rec f rs)) => Ord (ARec f rs) where-  compare x y = compare (fromARec x) (fromARec y)+module Data.Vinyl.ARec+  ( ARec -- Exported abstractly+  , IndexableField+  , toARec+  , fromARec+  , aget+  , aput+  , alens+  , arecGetSubset+  , arecSetSubset+  , arecRepsMatchCoercion+  , arecConsMatchCoercion+  ) where+import Data.Vinyl.ARec.Internal
+ Data/Vinyl/ARec/Internal.hs view
@@ -0,0 +1,193 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds #-}+#if __GLASGOW_HASKELL__ >= 806+{-# LANGUAGE QuantifiedConstraints #-}+{-# LANGUAGE RankNTypes #-}+#endif+{-# LANGUAGE RoleAnnotations #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+-- | Constant-time field accessors for extensible records. The+-- trade-off is the usual lists vs arrays one: it is fast to add an+-- element to the head of a list, but element access is linear time;+-- array access time is uniform, but extending the array is more+-- slower.+module Data.Vinyl.ARec.Internal+  ( ARec (..)+  , IndexableField+  , toARec+  , fromARec+  , aget+  , aput+  , alens+  , arecGetSubset+  , arecSetSubset+  , arecRepsMatchCoercion+  , arecConsMatchCoercion+  ) where+import Data.Vinyl.Core+import Data.Vinyl.Lens (RecElem(..), RecSubset(..))+import Data.Vinyl.TypeLevel++import qualified Data.Array as Array+import qualified Data.Array.Base as BArray+import GHC.Exts (Any)+import Unsafe.Coerce+#if __GLASGOW_HASKELL__ < 806+import Data.Constraint.Forall (Forall)+#endif+import Data.Coerce (Coercible)+import Data.Type.Coercion (Coercion (..))++-- | An array-backed extensible record with constant-time field+-- access.+newtype ARec (f :: k -> *) (ts :: [k]) = ARec (Array.Array Int Any)+type role ARec representational nominal++-- | Given that @xs@ and @ys@ have the same length, and mapping+-- @f@ over @xs@ and @g@ over @ys@ produces lists whose elements+-- are pairwise 'Coercible', @ARec f xs@ and @ARec g ys@ are+-- 'Coercible'.+arecRepsMatchCoercion :: AllRepsMatch f xs g ys => Coercion (ARec f xs) (ARec g ys)+arecRepsMatchCoercion = Coercion++-- | Given that @forall x. Coercible (f x) (g x)@, produce a coercion from+-- @ARec f xs@ to @ARec g xs@. While the constraint looks a lot like+-- @Coercible f g@, it is actually weaker.++#if __GLASGOW_HASKELL__ >= 806+arecConsMatchCoercion ::+  (forall (x :: k). Coercible (f x) (g x)) => Coercion (ARec f xs) (ARec g xs)+arecConsMatchCoercion = Coercion+#else+arecConsMatchCoercion :: forall k (f :: k -> *) (g :: k -> *) (xs :: [k]).+  Forall (Similar f g) => Coercion (Rec f xs) (Rec g xs)+-- Why do we need this? No idea, really. I guess some change in+-- newtype handling for Coercible in 8.6?+arecConsMatchCoercion = unsafeCoerce (Coercion :: Coercion (Rec f xs) (Rec f xs))+#endif++{-+-- This is sensible, but the ergonomics are likely quite bad thanks to the+-- interaction between Coercible resolution and resolution in the presence of+-- quantified constraints. Is there a good way to do this?++arecConsMatchCoercible :: forall k f g rep (r :: TYPE rep).+     (forall (x :: k). Coercible (f x) (g x))+  => ((forall (xs :: [k]). Coercible (ARec f xs) (ARec g xs)) => r) -> r+arecConsMatchCoercible f = f+-}++-- | Convert a 'Rec' into an 'ARec' for constant-time field access.+toARec :: forall f ts. (NatToInt (RLength ts)) => Rec f ts -> ARec f ts+toARec = go id+  where go :: ([Any] -> [Any]) -> Rec f ts' -> ARec f ts+        go acc RNil = ARec $! Array.listArray (0, n - 1) (acc [])+        go acc (x :& xs) = go (acc . (unsafeCoerce x :)) xs+        n = natToInt @(RLength ts)+{-# INLINE toARec #-}++-- | Defines a constraint that lets us index into an 'ARec' in order+-- to produce a 'Rec' using 'fromARec'.+class (NatToInt (RIndex t ts)) => IndexableField ts t where+instance (NatToInt (RIndex t ts)) => IndexableField ts t where++-- | Convert an 'ARec' into a 'Rec'.+fromARec :: forall f ts.+            (RecApplicative ts, RPureConstrained (IndexableField ts) ts)+         => ARec f ts -> Rec f ts+fromARec (ARec arr) = rpureConstrained @(IndexableField ts) aux+  where aux :: forall t. NatToInt (RIndex t ts) => f t+        aux = unsafeCoerce (arr Array.! natToInt @(RIndex t ts))+{-# INLINE fromARec #-}++-- | Get a field from an 'ARec'.+aget :: forall t f ts. (NatToInt (RIndex t ts)) => ARec f ts -> f t+aget (ARec arr) =+  unsafeCoerce (BArray.unsafeAt arr (natToInt @(RIndex t ts)))+{-# INLINE aget #-}++-- | Set a field in an 'ARec'.+aput :: forall t t' f ts ts'. (NatToInt (RIndex t ts))+      => f t' -> ARec f ts -> ARec f ts'+aput x (ARec arr) = ARec (arr Array.// [(i, unsafeCoerce x)])+  where i = natToInt @(RIndex t ts)+{-# INLINE aput #-}++-- | Define a lens for a field of an 'ARec'.+alens :: forall f g t t' ts ts'. (Functor g, NatToInt (RIndex t ts))+      => (f t -> g (f t')) -> ARec f ts -> g (ARec f ts')+alens f ar = fmap (flip (aput @t) ar) (f (aget ar))+{-# INLINE alens #-}++-- instance (i ~ RIndex t ts, i ~ RIndex t' ts', NatToInt (RIndex t ts)) => RecElem ARec t t' ts ts' i where+--   rlens = alens+--   rget = aget+--   rput = aput++instance RecElem ARec t t' (t ': ts) (t' ': ts) 'Z where+  rlensC = alens+  {-# INLINE rlensC #-}+  rgetC = aget+  {-# INLINE rgetC #-}+  rputC = aput @t+  {-# INLINE rputC #-}++instance (RIndex t (s ': ts) ~ 'S i, NatToInt i,  RecElem ARec t t' ts ts' i)+  => RecElem ARec t t' (s ': ts) (s ': ts') ('S i) where+  rlensC = alens+  {-# INLINE rlensC #-}+  rgetC = aget+  {-# INLINE rgetC #-}+  rputC = aput @t+  {-# INLINE rputC #-}++-- | Get a subset of a record's fields.+arecGetSubset :: forall rs ss f.+                 (IndexWitnesses (RImage rs ss), NatToInt (RLength rs))+              => ARec f ss -> ARec f rs+arecGetSubset (ARec arr) = ARec (Array.listArray (0, n-1) $+                                 go (indexWitnesses @(RImage rs ss)))+  where go :: [Int] -> [Any]+        go = map (arr Array.!)+        n = natToInt @(RLength rs)+{-# INLINE arecGetSubset #-}++-- | Set a subset of a larger record's fields to all of the fields of+-- a smaller record.+arecSetSubset :: forall rs ss f. (IndexWitnesses (RImage rs ss))+              => ARec f ss -> ARec f rs -> ARec f ss+arecSetSubset (ARec arrBig) (ARec arrSmall) = ARec (arrBig Array.// updates)+  where updates = zip (indexWitnesses @(RImage rs ss)) (Array.elems arrSmall)+{-# INLINE arecSetSubset #-}++instance (is ~ RImage rs ss, IndexWitnesses is, NatToInt (RLength rs))+         => RecSubset ARec rs ss is where+  rsubsetC f big = fmap (arecSetSubset big) (f (arecGetSubset big))+  {-# INLINE rsubsetC #-}++instance (RPureConstrained (IndexableField rs) rs,+          RecApplicative rs,+          Show (Rec f rs)) => Show (ARec f rs) where+  show = show . fromARec++instance (RPureConstrained (IndexableField rs) rs,+          RecApplicative rs,+          Eq (Rec f rs)) => Eq (ARec f rs) where+  x == y = fromARec x == fromARec y++instance (RPureConstrained (IndexableField rs) rs,+          RecApplicative rs,+          Ord (Rec f rs)) => Ord (ARec f rs) where+  compare x y = compare (fromARec x) (fromARec y)
Data/Vinyl/Core.hs view
@@ -10,8 +10,12 @@ {-# LANGUAGE PolyKinds             #-} {-# LANGUAGE RankNTypes            #-} {-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE Trustworthy           #-} {-# LANGUAGE TypeApplications      #-} {-# LANGUAGE TypeFamilies          #-}+#if __GLASGOW_HASKELL__ >= 806+{-# LANGUAGE QuantifiedConstraints #-}+#endif {-# LANGUAGE TypeOperators         #-} {-# LANGUAGE UndecidableInstances  #-} @@ -30,6 +34,7 @@ -- type. Instead, they treat the record as a list of fields, so will -- have performance linear in the size of the record. module Data.Vinyl.Core where+import Data.Coerce (Coercible) #if __GLASGOW_HASKELL__ < 808 import Data.Monoid (Monoid) #endif@@ -46,6 +51,11 @@ import Data.Type.Coercion (TestCoercion (..), Coercion (..)) import GHC.Generics import GHC.Types (Constraint, Type)+import Unsafe.Coerce (unsafeCoerce)+import Control.DeepSeq (NFData, rnf)+#if __GLASGOW_HASKELL__ < 806+import Data.Constraint.Forall (Forall)+#endif  -- | A record is parameterized by a universe @u@, an interpretation @f@ and a -- list of rows @rs@.  The labels or indices of the record are given by@@ -397,3 +407,97 @@          (Rep (Rec f rs)))   from (x :& xs) = M1 (M1 (K1 x) :*: M1 (from xs))   to (M1 (M1 (K1 x) :*: M1 xs)) = x :& to xs++instance ReifyConstraint NFData f xs => NFData (Rec f xs) where+  rnf = go . reifyConstraint @NFData+    where+      go :: forall elems. Rec (Dict NFData :. f) elems -> ()+      go RNil = ()+      go (Compose (Dict x) :& xs) = rnf x `seq` go xs++type family Head xs where+  Head (x ': _) = x+type family Tail xs where+  Tail (_ ': xs) = xs++type family AllRepsMatch_ (f :: j -> *) (xs :: [j]) (g :: k -> *) (ys :: [k]) :: Constraint where+  AllRepsMatch_ f (x ': xs) g ys =+    ( ys ~ (Head ys ': Tail ys)+    , Coercible (f x) (g (Head ys))+    , AllRepsMatch_ f xs g (Tail ys) )+  AllRepsMatch_ _ '[] _ ys = ys ~ '[]++-- | @AllRepsMatch f xs g ys@ means that @xs@ and @ys@ have the+-- same lengths, and that mapping @f@ over @xs@ and @g@ over @ys@+-- produces lists whose corresponding elements are 'Coercible' with+-- each other. For example, the following hold:+--+-- @AllRepsMatch Proxy '[1,2,3] Proxy '[4,5,6]@+-- @AllRepsMatch Sum '[Int,Word] Identity '[Min Int, Max Word]@+type AllRepsMatch f xs g ys = (AllRepsMatch_ f xs g ys, AllRepsMatch_ g ys f xs)++-- This two-sided approach means that the *length* of each list+-- can be inferred from the length of the other. I don't know how+-- useful that is in practice, but we get it almost for free.++-- | Given that for each element @x@ in the list @xs@,+repsMatchCoercion :: AllRepsMatch f xs g ys => Coercion (Rec f xs) (Rec g ys)+repsMatchCoercion = unsafeCoerce (Coercion :: Coercion () ())++{-+-- "Proof" that repsMatchCoercion is sensible.+repsMatchConvert :: AllRepsMatch f xs g ys => Rec f xs -> Rec g ys+repsMatchConvert RNil = RNil+repsMatchConvert (x :& xs) = coerce x :& repsMatchConvert xs+-}++#if __GLASGOW_HASKELL__ >= 806+consMatchCoercion ::+  (forall (x :: k). Coercible (f x) (g x)) => Coercion (Rec f xs) (Rec g xs)+#else+consMatchCoercion :: forall k (f :: k -> *) (g :: k -> *) (xs :: [k]).+  Forall (Similar f g) => Coercion (Rec f xs) (Rec g xs)+#endif+consMatchCoercion = unsafeCoerce (Coercion :: Coercion () ())+{-+-- "Proof" that consMatchCoercion is sensible.+consMatchConvert ::+  (forall (x :: k). Coercible (f x) (g x)) => Rec f xs -> Rec g xs+consMatchConvert RNil = RNil+consMatchConvert (x :& xs) = coerce x :& consMatchConvert xs++-- And for old GHC.+consMatchConvert' :: forall k (f :: k -> *) (g :: k -> *) (xs :: [k]).+  Forall (Similar f g) => Rec f xs -> Rec g xs+consMatchConvert' RNil = RNil+consMatchConvert' ((x :: f x) :& xs) =+  case inst :: Forall (Similar f g) DC.:- Similar f g x of+    DC.Sub DC.Dict -> coerce x :& consMatchConvert' xs+-}++{-+-- This is sensible, but I suspect the ergonomics will be awful+-- thanks to the interaction between Coercible constraint resolution+-- and constraint resolution with quantified constraints. Is there+-- a good way to accomplish it?++-- | Given+--+-- @+-- forall x. Coercible (f x) (g x)+-- @+--+-- provide the constraint+--+-- @+-- forall xs. Coercible (Rec f xs) (Rec g xs)+-- @+consMatchCoercible :: forall k f g rep (r :: TYPE rep).+     (forall (x :: k). Coercible (f x) (g x))+  => ((forall (xs :: [k]). Coercible (Rec f xs) (Rec g xs)) => r) -> r+consMatchCoercible f = case unsafeCoerce @(Zouch f f) @(Zouch f g) (Zouch $ \r -> r) of+  Zouch q -> q f++newtype Zouch (f :: k -> *) (g :: k -> *) =+  Zouch (forall rep (r :: TYPE rep). ((forall (xs :: [k]). Coercible (Rec f xs) (Rec g xs)) => r) -> r)+-}
Data/Vinyl/SRec.hs view
@@ -75,13 +75,17 @@ import Foreign.Ptr (Ptr) import Foreign.Storable (Storable(..)) import System.IO.Unsafe (unsafePerformIO, unsafeDupablePerformIO)+#if __GLASGOW_HASKELL__ >= 900+import Unsafe.Coerce (unsafeCoerce#)+import GHC.Prim (touch#, RealWorld)+#else+import GHC.Prim (touch#, unsafeCoerce#, RealWorld)+#endif  import GHC.IO (IO(IO)) import GHC.Base (realWorld#) import GHC.TypeLits (Symbol)- import GHC.Prim (MutableByteArray#, newAlignedPinnedByteArray#, byteArrayContents#)-import GHC.Prim (unsafeCoerce#, touch#, RealWorld) import GHC.Ptr (Ptr(..)) import GHC.Types (Int(..)) 
Data/Vinyl/TypeLevel.hs view
@@ -21,12 +21,8 @@  module Data.Vinyl.TypeLevel where -#if __GLASGOW_HASKELL__ < 806+import Data.Coerce import Data.Kind-#else-import GHC.Exts-#endif-import GHC.Types (Type)  -- | A mere approximation of the natural numbers. And their image as lifted by -- @-XDataKinds@ corresponds to the actual natural numbers.@@ -126,3 +122,8 @@ type family MapTyCon t xs = r | r -> xs where   MapTyCon t '[] = '[]   MapTyCon t (x ': xs) = ApplyToField t x ': MapTyCon t xs++-- | This class is used for `consMatchCoercion` with older versions+-- of GHC.+class Coercible (f x) (g x) => Similar f g (x :: k)+instance Coercible (f x) (g x) => Similar f g (x :: k)
tests/Aeson.hs view
@@ -33,6 +33,7 @@ -- another, nested, 'Array' for the rest of the record. We include -- here a function to flatten that recursive structure into the -- 'Object' shape we want.+module Main where import Control.Lens (view, deep) import Control.Monad.State.Strict import qualified Data.HashMap.Strict as H
tests/doctests.hs view
@@ -1,6 +1,14 @@+{-# language CPP #-} import Test.DocTest  main :: IO ()-main = doctest [ "tests/Intro.lhs"+main = doctest [ "-package lens"+               , "-package doctest"+#if __GLASGOW_HASKELL__ >= 900            +               , "-package singletons-th"+#else+               , "-package singletons"+#endif+               , "tests/Intro.lhs"                , "Data/Vinyl/Functor.hs"                , "Data/Vinyl/Curry.hs" ]
vinyl.cabal view
@@ -1,5 +1,5 @@ name:                vinyl-version:             0.13.0+version:             0.13.1 synopsis:            Extensible Records -- description: license:             MIT@@ -12,7 +12,7 @@ build-type:          Simple cabal-version:       >=1.10 extra-source-files:  CHANGELOG.md-tested-with:         GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.3, GHC == 8.10.1+tested-with:         GHC == 8.4.4, GHC == 8.6.5, GHC == 8.8.4, GHC == 8.10.4, GHC == 9.0.1  description: Extensible records for Haskell with lenses. @@ -23,6 +23,7 @@ library   exposed-modules:     Data.Vinyl                      , Data.Vinyl.ARec+                     , Data.Vinyl.ARec.Internal                      , Data.Vinyl.Class.Method                      , Data.Vinyl.Core                      , Data.Vinyl.CoRec@@ -40,7 +41,10 @@                      , Data.Vinyl.XRec   build-depends:       base >= 4.11 && <= 5,                        ghc-prim,+                       deepseq,                        array+  if impl (ghc < 8.6.0)+    build-depends: constraints >= 0.6.1   default-language:    Haskell2010   ghc-options:         -Wall   other-extensions:    TypeApplications@@ -90,7 +94,10 @@   hs-source-dirs:   tests   other-modules:    Intro   main-is:          doctests.hs-  build-depends:    base, lens, doctest >= 0.8, singletons >= 0.10, vinyl+  if impl (ghc < 9.0.1)+    build-depends:    base, lens, doctest >= 0.8, singletons >= 0.10 && < 3, vinyl+  else+    build-depends:    base, lens, doctest >= 0.8, singletons-th >= 3 && < 3.1, vinyl   default-language: Haskell2010  test-suite aeson