by-other-names 1.2.0.0 → 1.2.0.1
raw patch · 4 files changed
+108/−15 lines, 4 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- ByOtherNames: aliasListBegin :: forall before a tree. AliasTree before tree '[] => AliasList before a -> Aliases tree a
+ ByOtherNames: aliasListBegin :: forall names a rep. AliasTree names rep '[] => AliasList names a -> Aliases rep a
- ByOtherNames.Aeson: aliasListBegin :: forall before a tree. AliasTree before tree '[] => AliasList before a -> Aliases tree a
+ ByOtherNames.Aeson: aliasListBegin :: forall names a rep. AliasTree names rep '[] => AliasList names a -> Aliases rep a
- ByOtherNames.Internal: aliasListBegin :: forall before a tree. AliasTree before tree '[] => AliasList before a -> Aliases tree a
+ ByOtherNames.Internal: aliasListBegin :: forall names a rep. AliasTree names rep '[] => AliasList names a -> Aliases rep a
Files
- CHANGELOG.md +5/−0
- by-other-names.cabal +1/−1
- lib/ByOtherNames.hs +11/−0
- lib/ByOtherNames/Internal.hs +91/−14
CHANGELOG.md view
@@ -1,4 +1,9 @@ +1.2.0.1+=======++- A bit more documentation.+ 1.2.0.0 =======
by-other-names.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: by-other-names-version: 1.2.0.0+version: 1.2.0.1 synopsis: Give aliases to record fields. description: Give aliases to record fields.
lib/ByOtherNames.hs view
@@ -19,6 +19,7 @@ Rubric (..), Aliased (aliases), -- * Generic helpers+ -- $helpers GHasDatatypeName(..), GHasFieldNames (..), GRecord (..),@@ -31,3 +32,13 @@ where import ByOtherNames.Internal++{- $helpers++These generic helpers allow you to define typeclass instances for your datatypes+in one go, without having to divide your logic across auxiliary instances, or+deal with types of the generic representation like "GHC.Generics.D1".++You still need to use "GHC.Generics.Rep", @from@, and @to@. ++-}
lib/ByOtherNames/Internal.hs view
@@ -43,12 +43,13 @@ Rubric (..), -- * Generic helpers- GHasDatatypeName(..),+ GHasDatatypeName (..), GHasFieldNames (..), GRecord (..), GHasBranchNames (..), GSum (..), Slots (..),+ -- * Re-exports Symbol, )@@ -87,12 +88,12 @@ zipAliasesWith :: (a -> b -> c) -> Aliases rep a -> Aliases rep b -> Aliases rep c zipAliasesWith f a1 a2 = case (a1, a2) of- (Field a, Field b) -> Field (f a b)- (Branch a, Branch b) -> Branch (f a b)- (FieldTree a1 a2, FieldTree b1 b2) -> FieldTree (zipAliasesWith f a1 b1) (zipAliasesWith f a2 b2)- (BranchTree a1 a2, BranchTree b1 b2) -> BranchTree (zipAliasesWith f a1 b1) (zipAliasesWith f a2 b2)- (Sum a, Sum b) -> Sum (zipAliasesWith f a b)- (Record a, Record b) -> Record (zipAliasesWith f a b)+ (Field a, Field b) -> Field (f a b)+ (Branch a, Branch b) -> Branch (f a b)+ (FieldTree a1 a2, FieldTree b1 b2) -> FieldTree (zipAliasesWith f a1 b1) (zipAliasesWith f a2 b2)+ (BranchTree a1 a2, BranchTree b1 b2) -> BranchTree (zipAliasesWith f a1 b1) (zipAliasesWith f a2 b2)+ (Sum a, Sum b) -> Sum (zipAliasesWith f a b)+ (Record a, Record b) -> Record (zipAliasesWith f a b) instance Functor (Aliases rep) where fmap f as = case as of@@ -160,9 +161,34 @@ -- | Define the aliases for a type by listing them. -- -- See also 'alias' and 'aliasListEnd'.-aliasListBegin :: forall before a tree. (AliasTree before tree '[]) => AliasList before a -> Aliases tree a+--+-- The type of the argument is indexed by a list of 'Symbol's, while the +-- type of the result is indexed by a generic 'Rep'.+--+-- Example for a record:+--+-- >>> :{+-- data Foo = Foo {aa :: Int, bb :: Bool}+-- deriving (Read, Show, Generic)+-- fieldAliases :: Aliases (Rep Foo) String+-- fieldAliases = aliasListBegin $ alias @"aa" "alias1" $ alias @"bb" "alias2" $ aliasListEnd+-- :}+--+-- Example for a sum:+--+-- >>> :{+-- data Bar = Aa Int | Bb+-- deriving (Read, Show, Generic)+-- branchAliases :: Aliases (Rep Bar) String+-- branchAliases = aliasListBegin $ alias @"Aa" "alias1" $ alias @"Bb" "alias2" $ aliasListEnd+-- :}+--+--+aliasListBegin :: forall names a rep. (AliasTree names rep '[]) + => AliasList names a + -> Aliases rep a aliasListBegin names =- let (aliases, Null) = parseAliasTree @before @tree names+ let (aliases, Null) = parseAliasTree @names @rep names in aliases -- | The empty `AliasList`.@@ -256,21 +282,22 @@ -- the datatype during deriving. -- If you are using 'Aliases' in standalone functions (possibly in combination with--- 'GRecord' and 'GSum') you might not need to define a 'Rubric'. +-- 'GRecord' and 'GSum') you might not need to define a 'Rubric'. type Rubric :: k -> Constraint class Rubric k where type AliasType k :: Type +-- | Given a datatype's 'Rep', obtain the datatype's name. class GHasDatatypeName rep where gGetDatatypeName :: String instance KnownSymbol datatypeName => GHasDatatypeName (D1 (MetaData datatypeName m p nt) (C1 y prod)) where gGetDatatypeName = symbolVal (Proxy @datatypeName) +-- | Given a datatype's 'Rep', obtain its field names, assuming the datatype is a record. class GHasFieldNames rep where gGetFieldNames :: Aliases rep String - instance GHasFieldNames prod => GHasFieldNames (D1 x (C1 y prod)) where gGetFieldNames = Record (gGetFieldNames @prod) @@ -283,7 +310,7 @@ where gGetFieldNames = FieldTree (gGetFieldNames @left) (gGetFieldNames @right) -+-- | Given a datatype's 'Rep', obtain its brach names, assuming the datatype is a sum. class GHasBranchNames rep where gGetBranchNames :: Aliases rep String @@ -304,20 +331,32 @@ instance KnownSymbol branchName => GHasBranchNames (C1 ('MetaCons branchName fixity sels) y) where gGetBranchNames = Branch (symbolVal (Proxy @branchName)) ---+-- | Helper typeclass for defining typeclass instances for record types. --+-- Parameterized by a constraint @c@ that each field of the record must satisfy, and by+-- the generic 'Rep' of the record. class GRecord (c :: Type -> Constraint) rep where+ -- | Builds a parser for the entire generic 'Rep' out of parsers for each field. gToRecord :: Applicative m =>+ -- | Field aliases. Aliases rep a -> (forall v. c v => a -> m v) -> m (rep z)++ -- | Returns an uniform representation of each field's value in a record.+ --+ -- Useful for serializing. gFromRecord ::+ -- | Field aliases. Aliases rep a -> (forall v. c v => a -> v -> o) -> rep z -> Aliases rep o++ -- | Decorates an 'Aliases' value with values derived from the type of the corresponding fields. gRecordEnum ::+ -- | Field aliases. Aliases rep a -> (forall v. c v => Proxy v -> o) -> Aliases rep (a, o)@@ -332,7 +371,7 @@ instance c v => GRecord c (S1 x (Rec0 v)) where gToRecord (Field a) parseField = M1 . K1 <$> parseField a- gFromRecord (Field a) renderField (M1 (K1 v)) = Field ( renderField a v )+ gFromRecord (Field a) renderField (M1 (K1 v)) = Field (renderField a v) gRecordEnum (Field a) renderField = Field (a, renderField (Proxy @v)) instance@@ -346,28 +385,51 @@ gRecordEnum (FieldTree aleft aright) renderField = FieldTree (gRecordEnum @c @left aleft renderField) (gRecordEnum @c @right aright renderField) +-- | Helper for defining branch parsers. --+-- @v@ is some part of a generic 'Rep', @m1@ is some parser type for when there's a single+-- field in the branch, and @m2@ is some parser type for when there's more than one field+-- in the branch. --+-- @m1@ and @m2@ might be the same type. data Slots m1 m2 v = ZeroSlots v | SingleSlot (m1 v) | ManySlots (m2 v) deriving stock (Show, Functor) +-- | Helper typeclass for defining typeclass instances for sum types.+--+-- Parameterized by a constraint @c@ that each field in each branch of the sum must satisfy, and by+-- the generic 'Rep' of the sum. class GSum (c :: Type -> Constraint) rep where+ -- | Builds a parser for the entire generic 'Rep'. gToSum :: (Functor n, Applicative m2) =>+ -- | Branch aliases. Aliases rep a ->+ -- | Convert a parser for a branch's fields into a parser for the branch. (forall b. a -> Slots m1 m2 b -> n b) ->+ -- | Parser for when there's only one field in a branch. (forall v. c v => m1 v) ->+ -- | Parser for when there's more than one field in a branch. (forall v. c v => m2 v) -> Aliases rep (n (rep z))++ -- | Returns the annotation corresponding to the current branch,+ -- along with an uniform representation of the branch field's values.+ --+ -- Useful for serializing. gFromSum ::+ -- | Branch aliases. Aliases rep a -> (forall v. c v => v -> o) -> rep z -> (a, [o])++ -- | Decorates an 'Aliases' value with values derived from the type of each branch's fields. gSumEnum ::+ -- | Branch aliases. Aliases rep a -> (forall v. c v => Proxy v -> o) -> Aliases rep (a, [o])@@ -443,3 +505,18 @@ gFromSumSlots @c renderSlot left ++ gFromSumSlots @c renderSlot right gSumEnumSlots renderSlot = gSumEnumSlots @c @left renderSlot ++ gSumEnumSlots @c @right renderSlot+++-- $setup+--+-- >>> :set -XBlockArguments+-- >>> :set -XTypeApplications+-- >>> :set -XDerivingStrategies+-- >>> :set -XDerivingVia+-- >>> :set -XDataKinds+-- >>> :set -XMultiParamTypeClasses+-- >>> :set -XDeriveGeneric+-- >>> :set -XOverloadedStrings+-- >>> import ByOtherNames+-- >>> import GHC.Generics+-- >>> import GHC.TypeLits