packages feed

red-black-record 2.1.1.0 → 2.1.2.0

raw patch · 6 files changed

+85/−56 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.RBR: [runCase] :: Case f a b -> f b -> a
+ Data.RBR: injections'_Variant :: Maplike t => Record (Case f (Variant f t)) t
+ Data.RBR.Internal: [runCase] :: Case f a b -> f b -> a
+ Data.RBR.Internal: injections'_Variant :: Maplike t => Record (Case f (Variant f t)) t

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for red-black-record +## 2.1.2.0+- Deprecated VariantInjection and injections_Variant. VariantInjections is+  superfluous, as Case can be used instead.+- Added runCase accessor for Case.+ ## 2.1.1.0 - Added NP-like functions for working on Records, like sequence_Record.   They are memebers of the Maplike typeclass.
lib/Data/RBR.hs view
@@ -16,6 +16,8 @@         - @q@: The kind of the type value @v@.         - @f@: A type constructor of kind @q -> Type@ that wraps the type @v@.          - @flat@: A type-level list of kind @[q]@ whose elements correspond to values in a type-level 'Map'.+     +    See the "Data.RBR.Examples" module for examples of usage and links to external resources.          -} module Data.RBR (@@ -72,7 +74,6 @@        Maplike(..),        cpure_Record,        cpure'_Record,-       VariantInjection(..),        prettyShow_Record,        prettyShow_RecordI,        prettyShow_Variant,@@ -110,6 +111,8 @@        (:.:)(..),        -- * Deprecated        collapse_Record,+       injections_Variant,+       VariantInjection(..),        eliminate,        prettyShowRecord,        prettyShowRecordI,
lib/Data/RBR/Examples.hs view
@@ -49,11 +49,10 @@ >>> :set -Wno-partial-type-signatures   >>> import Data.RBR >>> import qualified Data.RBR.Subset as S->>> import Data.SOP->>> import Data.SOP.NP (cpure_NP,sequence_NP,liftA2_NP,collapse_NP) >>> import Data.String >>> import Data.Proxy >>> import Data.Foldable+>>> import Data.Monoid >>> import Data.Profunctor (Star(..)) >>> import GHC.Generics (Generic) >>> import GHC.TypeLits@@ -132,10 +131,10 @@     eventually returns. The internal branches of the 'Variant' can be removed with     'winnow'.  -    This library makes it more involved than it should be, because inserting an-    entry and then deleting it can result in structurally dissimilar type-level-    maps. So we need extra type annotations in 'winnow', and also a call to-    'injectSubset' to perform the conversion.+    This is doable in red-black-record, but it becomes more involved than it+    should because inserting an entry and then deleting it can result in+    structurally dissimilar type-level maps. So we need extra type annotations+    in 'winnow', and also a call to 'injectSubset' to perform the conversion.   >>> type Smaller = FromList '[ '("foo",Char), '("bar",Int) ] >>> :{@@ -168,18 +167,19 @@  {- $json1  -    We start in the @sop-core@ world, creating a product of parsing functions-    (one for each field) using 'cpure_NP'. --    Then we convert that product to a 'Record', apply to it a transformation-    that uses field selectors, and convert it back to a product.+    We begin by creating a 'Record' of parsing functions, each paired with its+    corresponding field name. We use 'Star' to treat the functions directly as+    'Applicative's.+    +    Then we apply the transformation that we receive as parameter, which tweaks+    the parsing functions and/or the field names.  -    Then we demote the field names and combine them with the product of-    'Data.Aeson.Value' parsers using 'liftA2_NP', getting a product of-    'Data.Aeson.Object' parsers.+    We transform the result into a 'Record' of functions that parse a+    'Data.Aeson.Object'. Then we pull out the parsing function 'Aplicative'+    using 'sequence_Record', ending up with a parsing function that returns a+    pure 'Record'.  -    Then we use 'sequence_NP' to convert the product of parsers into a parser-    of 'Record'.+    The last step is to construct the nominal record type using 'fromRecord'.  >>> :{     let parseSpecial@@ -232,9 +232,9 @@              in withObject "someobj" $ \o -> fromRecord <$> objectParser o     :} -   We have to use 'getFieldSubset' because the aliases are listed in a+   We have to use 'getFieldSubset' because the aliases might be listed in a    different order than the record fields, and that might result in different-   type-level trees. If the orders were the same, we wouldn't need it. +   type-level trees.  >>> data Person = Person { name :: String, age :: Int } deriving (Generic, Show) >>> instance ToRecord Person @@ -292,19 +292,25 @@  {- $json4sum  -    To ensure that we don't forget any branch when parsing a sum type from JSON, -    we can create a n-ary product of parsers, one for each branch.+    To ensure that we don't forget any branch when parsing a sum type from+    JSON, we begin by creating a 'Record' of parsing functions, one for each+    branch. We use 'cpure'_Record' to get hold of the field names while+    constructing the parsing functions. -    Then we create a n-ary product of injections. Each component of the-    product creates a n-ary sum out of the value of the corresponding branch.+    Then we create a 'Record' of injections using 'injections'_Variant'. Each+    component of the 'Record' injects a value of the field's type into the+    corresponding branch of the 'Variant'. -    We combine the n-ary product of parsers with the n-ary product of-    injections, and collapse all the resulting parsers with-    'Control.Applicative.asum'.+    We combine the injections with the parsing functions using 'liftA2_Record'.+    We use the constant functor 'K' as the wrapping type of the result, and+    inside it an 'Alt' newtype to get a 'Monoid' instance for the parsing+    functions. -    Then we convert the n-ary sum value that "wins" into a 'Variant' and-    finally back into the original type.+    The we collapse the record with 'collapse'_Record', resulting in a single+    parsing function that handles all possible branches. +    The last step is to construct the nominal sum type using 'fromVariant'.+ >>> :{     let parseAll               :: forall r c flat. (IsVariantType r c, @@ -315,8 +321,8 @@         parseAll =              let fieldParsers = cpure'_Record (Proxy @FromJSON) $ \fieldName ->                      Star (\o -> explicitParseField parseJSON o (Data.Text.pack fieldName))-                injected = liftA2_Record (\f star -> K [ runVariantInjection f . I <$> star ]) injections_Variant fieldParsers -                Star parser = asum $ collapse'_Record injected+                injected = liftA2_Record (\f star -> K $ Alt $ runCase f . I <$> star) injections'_Variant fieldParsers +                Alt (Star parser) = collapse'_Record injected              in withObject "someobj" (\o -> fromVariant <$> parser o)     :} 
lib/Data/RBR/Internal.hs view
@@ -140,15 +140,17 @@     liftA_Variant :: (forall a. f a -> g a) -> Variant f t -> Variant g t     {- | Given a 'Record' of transformation, apply the one which matches the active branch of 'Variant'.      -         The naming scheme follows that of 'Data.SOP.NS.liftA_NS'.+         The naming scheme follows that of 'Data.SOP.NS.liftA2_NS'.     -}     liftA2_Variant :: (forall a. f a -> g a -> h a) -> Record f t -> Variant g t -> Variant h t     {- |           Construct a 'Record' made of functions which take a value of the          field's type and inject it in the 'Variant' branch which corresponds          to the field.++         Compare to 'Data.SOP.NS.injections' from @generics-sop@.     -}-    injections_Variant :: Record (VariantInjection f t) t+    injections'_Variant :: Record (Case f (Variant f t)) t     {- | Collapse a 'Record' composed of 'K' monoidal annotations.              >>> collapse'_Record (unit :: Record (K [Bool]) Empty)@@ -171,7 +173,7 @@     liftA2_Record _ Empty Empty = Empty     liftA_Variant _ neverHappens = impossible neverHappens     liftA2_Variant _ Empty neverHappens = impossible neverHappens-    injections_Variant = Empty+    injections'_Variant = Empty     collapse'_Record Empty = mempty     collapse_Variant = impossible @@ -189,21 +191,21 @@         Here  fv -> Here (trans rv fv)         LookLeft leftV -> LookLeft (liftA2_Variant trans left leftV)         LookRight rightV -> LookRight (liftA2_Variant trans right rightV)-    injections_Variant = -        let injections_Left = liftA_Record (\(VariantInjection j) -> VariantInjection $ LookLeft . j) (injections_Variant @left)-            injections_Right = liftA_Record (\(VariantInjection j) -> VariantInjection $ LookRight . j) (injections_Variant @right)-         in Node injections_Left (VariantInjection $ Here) injections_Right+    injections'_Variant = +        let injections_Left = liftA_Record (\(Case j) -> Case $ LookLeft . j) (injections'_Variant @left)+            injections_Right = liftA_Record (\(Case j) -> Case $ LookRight . j) (injections'_Variant @right)+         in Node injections_Left (Case $ Here) injections_Right     collapse'_Record (Node left (K v) right) = collapse'_Record left <> (v <> collapse'_Record right)      collapse_Variant vv = case vv of         Here (K a) -> a         LookLeft leftV -> collapse_Variant leftV         LookRight rightV -> collapse_Variant rightV -{- |-    A function which takes the value of a field and injects it into the corresponding branch of a 'Variant'.+{-# DEPRECATED injections_Variant "Use injections'_Variant instead" #-}+injections_Variant :: Maplike t => Record (VariantInjection f t) t+injections_Variant = liftA_Record (\(Case f) -> VariantInjection f) injections'_Variant  -    See also 'Data.SOP.NS.Injection'.- -}+{-# DEPRECATED VariantInjection "Use Case instead" #-} newtype VariantInjection (f :: q -> Type) (t :: Map Symbol q) (v :: q) = VariantInjection { runVariantInjection :: f v -> Variant f t }  instance KeysValuesAll c E where@@ -253,10 +255,10 @@      of type 'String'. This means that there aren't actually any values of the      type that corresponds to each field, only the 'String' annotations. ->>> putStrLn $ prettyShow_Record show $ demoteKeys @(Insert "foo" Char (Insert "bar" Bool Empty))+>>> putStrLn $ prettyShow_Record show $ demoteKeys @(FromList [ '("foo",Char), '("bar",Bool) ]) {bar = K "bar", foo = K "foo"} -     For computations involving field names, sometimes 'cpure\'_Record' is a better option.+     For computations involving field names, sometimes 'cpure'_Record' is a better option.  -}  demoteKeys :: forall t. KeysValuesAll KnownKey t => Record (K String) t@@ -281,7 +283,7 @@   Create a record containing the names of each field along with a term-level   representation of each type. ->>> putStrLn $ prettyShow_Record show $ demoteEntries @(Insert "foo" Char (Insert "bar" Bool Empty))+>>> putStrLn $ prettyShow_Record show $ demoteEntries @(FromList [ '("foo",Char), '("bar",Bool) ]) {bar = K ("bar",Bool), foo = K ("foo",Char)}    See also 'collapse_Record' for getting the entries as a list.@@ -950,7 +952,7 @@  {- | Represents a handler for a branch of a 'Variant'.   -}-newtype Case f a b = Case (f b -> a)+newtype Case f a b = Case { runCase :: f b -> a }  instance Functor f => Contravariant (Case f a) where     contramap g (Case c) = Case (c . fmap g)@@ -1140,7 +1142,15 @@  {- | Convert a n-ary product into a compatible 'Record'. Usually follows an invocation of 'toNP'.  ->>> prettyShow_RecordI . fromNP @(Insert "foo" _ (Insert "bar" _ Empty)) . toNP $ insertI @"foo" 'a' (insertI @"bar" True unit)++>>> :{ +    prettyShow_RecordI $ +    fromNP @(Insert "foo" _ (Insert "bar" _ Empty)) $+    toNP $ +    insertI @"foo" 'a' $+    insertI @"bar" True $+    unit+:} "{bar = True, foo = 'a'}"  -}@@ -1242,7 +1252,12 @@  {- | Convert a n-ary sum into a compatible 'Variant'.   ->>> prettyShow_VariantI $ fromNS @(Insert "foo" _ (Insert "bar" _ Empty)) . toNS $ (injectI @"foo" 'a' :: Variant I (Insert "foo" Char (Insert "bar" Bool Empty)))+>>> :{ +    prettyShow_VariantI $ +    fromNS @(FromList [ '("foo",_), '("bar",_) ]) $ +    toNS $ +    (injectI @"foo" 'a' :: Variant I (FromList [ '("foo",Char), '("bar",Bool) ]))+:} "foo ('a')"  -}@@ -1968,10 +1983,10 @@  {- | Like 'winnow' but specialized to pure 'Variant's.  ->>> winnow @"bar" @Bool (injectI @"bar" False :: Variant I (Insert "foo" Char (Insert "bar" Bool Empty)))+>>> winnow @"bar" @Bool (injectI @"bar" False :: Variant I (FromList [ '("foo",Char), '("bar",Bool) ])) Right (I False) ->>> prettyShow_VariantI `first` winnow @"foo" @Char (injectI @"bar" False :: Variant I (Insert "foo" Char (Insert "bar" Bool Empty)))+>>> prettyShow_VariantI `first` winnow @"foo" @Char (injectI @"bar" False :: Variant I (FromList [ '("foo",Char), '("bar",Bool) ])) Left "bar (False)"   -}
lib/Data/RBR/Subset.hs view
@@ -3,7 +3,7 @@     work with a subset of the fields of a 'Record' or the branches of a     'Variant'.     -    __Edit:__ There are functions of the same name in the 'Data.RBR' module,+    __Note:__ There are functions of the same name in the 'Data.RBR' module,     but they are deprecated. The functions from this module should be used     instead, preferably qualified. The changes have to do mainly with the     required constraints.@@ -41,8 +41,8 @@         branchSubset,         injectSubset,         matchSubset, -        eliminateSubset,-        fromRecordSuperset+        fromRecordSuperset,+        eliminateSubset     ) where  import Data.Proxy@@ -156,7 +156,7 @@ branchSubset :: forall subset whole f. (Maplike subset, Maplike whole, Subset subset whole)              => (Variant f whole -> Maybe (Variant f subset), Variant f subset -> Variant f whole) branchSubset = -    let inj2case = \adapt (VariantInjection vif) -> Case $ \fv -> adapt (vif fv) -- (\fv -> adapt (fromNS @t (unK (apFn fn fv))))+    let inj2case = \adapt (Case vif) -> Case $ \fv -> adapt (vif fv)          -- The intuition is that getting the setter and the getter together might be faster at compile-time.         -- The intuition might be wrong.         subs :: forall f. Record f whole -> (Record f subset -> Record f whole, Record f subset)@@ -164,14 +164,14 @@      in      (,)      (let injs :: Record (Case f (Maybe (Variant f subset))) subset -          injs = liftA_Record (inj2case Just) (injections_Variant @subset)+          injs = liftA_Record (inj2case Just) (injections'_Variant @subset)           -- fixme: possibly inefficient?           wholeinjs :: Record (Case f (Maybe (Variant f subset))) whole            wholeinjs = pure_Record (Case (\_ -> Nothing))           mixedinjs = fst (subs wholeinjs) injs        in eliminate_Variant mixedinjs)      (let wholeinjs :: Record (Case f (Variant f whole)) whole-          wholeinjs = liftA_Record (inj2case id) (injections_Variant @whole)+          wholeinjs = liftA_Record (inj2case id) (injections'_Variant @whole)           injs = snd (subs wholeinjs)        in eliminate_Variant injs) 
red-black-record.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.0 name:                red-black-record-version:             2.1.1.0+version:             2.1.2.0 synopsis:            Extensible records and variants indexed by a type-level Red-Black tree.  description:         A library that provides extensible records and variants,