packages feed

hkd-records 0.0.1 → 0.0.2

raw patch · 3 files changed

+96/−66 lines, 3 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Data.HKD.Records: class FLabels t
- Data.HKD.Records: data HkdProd (f :: a -> *) g t
- Data.HKD.Records: data LkdProd f g (x :: a)
- Data.HKD.Records: flabels :: FLabels t => t (Const Text)
- Data.HKD.Records: gfdicts :: forall t c. (Generic (t (Dict c)), GFDicts (Rep (t (Dict c)) ())) => t (Dict c)
- Data.HKD.Records: gflabels :: forall t. (Generic (t (Const Text)), GLabels (Rep (t (Const Text)) ())) => t (Const Text)
- Data.HKD.Records: gflenses :: forall k t r g. GFlensesMachinery k t r g => t (FLens g t)
- Data.HKD.Records: instance (Data.HKD.Records.GLabels (f ()), Data.HKD.Records.GLabels (g ())) => Data.HKD.Records.GLabels ((GHC.Generics.:*:) f g ())
- Data.HKD.Records: instance Data.HKD.Records.GLabels (b ()) => Data.HKD.Records.GLabels (GHC.Generics.D1 meta (GHC.Generics.C1 meta2 b) ())
- Data.HKD.Records: instance forall (label :: GHC.Maybe.Maybe GHC.Types.Symbol) (_x :: GHC.Generics.SourceUnpackedness) (_x2 :: GHC.Generics.SourceStrictness) (_x3 :: GHC.Generics.DecidedStrictness) k (g :: k -> *) (a :: k). Data.HKD.Records.GFLenses (GHC.Generics.S1 ('GHC.Generics.MetaSel label _x _x2 _x3) (GHC.Generics.Rec0 (g a))) k (Data.HKD.Records.FunctorS1 label _x _x2 _x3 a) g
- Data.HKD.Records: instance forall a (t :: (a -> *) -> *) (g :: ((a -> *) -> *) -> *) (g' :: a -> *) (f :: a -> *). (Data.HKD.FZip t, Data.HKD.Records.GFTranspose g t g') => Data.HKD.Records.GFTranspose (Data.HKD.Records.HkdProd f g) t (Data.HKD.Records.LkdProd f g')
- Data.HKD.Records: instance forall k (label :: GHC.Maybe.Maybe GHC.Types.Symbol) (_x :: GHC.Generics.SourceUnpackedness) (_x2 :: GHC.Generics.SourceStrictness) (_x3 :: GHC.Generics.DecidedStrictness) (a :: k). Data.HKD.FFunctor (Data.HKD.Records.Tupled (Data.HKD.Records.FunctorS1 label _x _x2 _x3 a))
- Data.HKD.Records: instance forall k (label :: GHC.Types.Symbol) (_x :: GHC.Generics.SourceUnpackedness) (_x2 :: GHC.Generics.SourceStrictness) (_x3 :: GHC.Generics.DecidedStrictness) (b :: k). GHC.TypeLits.KnownSymbol label => Data.HKD.Records.GLabels (GHC.Generics.S1 ('GHC.Generics.MetaSel ('GHC.Maybe.Just label) _x _x2 _x3) (GHC.Generics.Rec0 (Data.Functor.Const.Const Data.Text.Internal.Text b)) ())
+ Data.HKD.Records: class FieldNames t
+ Data.HKD.Records: data FieldCons f g (x :: a)
+ Data.HKD.Records: data RecordCons (f :: a -> *) g t
+ Data.HKD.Records: fieldNames :: FieldNames t => t (Const Text)
+ Data.HKD.Records: instance (Data.HKD.Records.GFieldNames (f ()), Data.HKD.Records.GFieldNames (g ())) => Data.HKD.Records.GFieldNames ((GHC.Generics.:*:) f g ())
+ Data.HKD.Records: instance Data.HKD.Records.GFieldNames (b ()) => Data.HKD.Records.GFieldNames (GHC.Generics.D1 meta (GHC.Generics.C1 meta2 b) ())
+ Data.HKD.Records: instance forall (fieldName :: GHC.Maybe.Maybe GHC.Types.Symbol) (_x :: GHC.Generics.SourceUnpackedness) (_x2 :: GHC.Generics.SourceStrictness) (_x3 :: GHC.Generics.DecidedStrictness) k (g :: k -> *) (a :: k). Data.HKD.Records.GFLenses (GHC.Generics.S1 ('GHC.Generics.MetaSel fieldName _x _x2 _x3) (GHC.Generics.Rec0 (g a))) k (Data.HKD.Records.FunctorS1 fieldName _x _x2 _x3 a) g
+ Data.HKD.Records: instance forall a (t :: (a -> *) -> *) (g :: ((a -> *) -> *) -> *) (g' :: a -> *) (f :: a -> *). (Data.HKD.FZip t, Data.HKD.Records.GFTranspose g t g') => Data.HKD.Records.GFTranspose (Data.HKD.Records.RecordCons f g) t (Data.HKD.Records.FieldCons f g')
+ Data.HKD.Records: instance forall k (fieldName :: GHC.Maybe.Maybe GHC.Types.Symbol) (_x :: GHC.Generics.SourceUnpackedness) (_x2 :: GHC.Generics.SourceStrictness) (_x3 :: GHC.Generics.DecidedStrictness) (a :: k). Data.HKD.FFunctor (Data.HKD.Records.Tupled (Data.HKD.Records.FunctorS1 fieldName _x _x2 _x3 a))
+ Data.HKD.Records: instance forall k (fieldName :: GHC.Types.Symbol) (_x :: GHC.Generics.SourceUnpackedness) (_x2 :: GHC.Generics.SourceStrictness) (_x3 :: GHC.Generics.DecidedStrictness) (b :: k). GHC.TypeLits.KnownSymbol fieldName => Data.HKD.Records.GFieldNames (GHC.Generics.S1 ('GHC.Generics.MetaSel ('GHC.Maybe.Just fieldName) _x _x2 _x3) (GHC.Generics.Rec0 (Data.Functor.Const.Const Data.Text.Internal.Text b)) ())
- Data.HKD.Records: (:>) :: f x -> g x -> LkdProd f g (x :: a)
+ Data.HKD.Records: (:>) :: f x -> g x -> FieldCons f g (x :: a)
- Data.HKD.Records: (:~>) :: t f -> g t -> HkdProd (f :: a -> *) g t
+ Data.HKD.Records: (:~>) :: t f -> g t -> RecordCons (f :: a -> *) g t
- Data.HKD.Records: class FLenses t
+ Data.HKD.Records: class FLenses (t :: (k -> *) -> *)

Files

CHANGELOG.md view
@@ -1,5 +1,12 @@ # Revision history for hkd-records -## 0.1.0.0 -- YYYY-mm-dd+## 0.0.1 -- 2022-07-22  * First version. Released on an unsuspecting world.++## 0.0.2 -- 2022-07-23++* added documentation+* changed generic functions to default member functions+* changed HkdProd and LkdProd type names+
hkd-records.cabal view
@@ -1,5 +1,5 @@ name:                hkd-records-version:             0.0.1+version:             0.0.2 cabal-version:       >=1.10 synopsis:  higher kinded record operations description: make higher kinded records great again
src/Data/HKD/Records.hs view
@@ -17,12 +17,47 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DefaultSignatures #-}++{-|+Module      : Data.HKD.Records+Description : Make higher kinded records great again+Copyright   : (c) Kristof Bastiaensen, 2022+License     : BSD-3+Maintainer  : kristof@resonata.be+Stability   : stable+Portability : ghc++This module contains additions for the hkd package to making it easier+for working with higher kinded records.  In particular, it gives+access to the fieldNames of a records using the `fieldNames` function,+allows you to zip many records together using `fzipManyWith`, and+allows functions with constraints by using the `fdicts` function.+This makes it possible to implement many generic functions using these+functions rather than having to implement complicated typeclasses for+Generics.  As an example, here is a (poor mans) url encoding function:++@+zipShow :: (FFoldable t, FRepeat t, FieldNames t, FDicts Show t, FZip t) =>+            t Identity -> Text+zipShow t =+   Text.concat $+   intersperse "&" $+   ftoList $ +   fzipManyWith+   (\(Identity y :> Const lbl :> Dict :> End) ->+       Const $ lbl <> "=" <> Text.pack (show y))+   (t :~> fieldNames :~> fdicts @Show :~> End)+@++-}+ module Data.HKD.Records (-  FLabels(..), gflabels,-  Dict(..), FDicts(..), gfdicts,-  HkdProd(..), LkdProd(..), End,+  FieldNames(..),+  Dict(..), FDicts(..),+  RecordCons(..), FieldCons(..), End,   fzipManyWith, ftoList, Lens', FLens(..),-  FLenses(..), gflenses) where+  FLenses(..)) where import Data.HKD import Data.Text (Text) import Data.Functor.Const@@ -32,46 +67,49 @@ import qualified Data.Text as Text import Data.Proxy import Data.Monoid-import Data.Functor.Identity-import Data.List -class FLabels t where-  -- | get the labels from each field as a (Const Text).-  flabels :: t (Const Text)+class FieldNames t where+  -- | get the fieldNames from each field as a (Const Text).  Can be+  -- auto derived for records with a Generic instance.+  default fieldNames :: (Generic (t (Const Text)),+                       GFieldNames (Rep (t (Const Text)) ()))+                  => t (Const Text)+  fieldNames = to (genFieldNames :: Rep (t (Const Text)) ())                  +  fieldNames :: t (Const Text) -class GLabels t where-  genFlabels :: t+class GFieldNames t where+  genFieldNames :: t   -instance (GLabels (f ()), GLabels (g ())) => GLabels ((f :*: g) ()) where-  genFlabels = genFlabels :*: genFlabels-  {-# INLINE genFlabels #-}+instance (GFieldNames (f ()), GFieldNames (g ())) => GFieldNames ((f :*: g) ()) where+  genFieldNames = genFieldNames :*: genFieldNames+  {-# INLINE genFieldNames #-} -instance KnownSymbol label =>-         (GLabels (S1 ('MetaSel ('Just label) _x _x2 _x3)+instance KnownSymbol fieldName =>+         (GFieldNames (S1 ('MetaSel ('Just fieldName) _x _x2 _x3)                     (Rec0 (Const Text b))                     ())) where-  genFlabels = M1 $ K1 $ Const (Text.pack $ symbolVal (Proxy @label))-  {-# INLINE genFlabels #-}+  genFieldNames = M1 $ K1 $ Const (Text.pack $ symbolVal (Proxy @fieldName))+  {-# INLINE genFieldNames #-}   -instance GLabels (b ()) => (GLabels ((D1 meta (C1 meta2 b)) ())) where-  genFlabels = M1 $ M1 $ genFlabels-  {-# INLINE genFlabels #-}+instance GFieldNames (b ()) => (GFieldNames ((D1 meta (C1 meta2 b)) ())) where+  genFieldNames = M1 $ M1 $ genFieldNames+  {-# INLINE genFieldNames #-} --- | Automatically derive flabels using generics.  This only requires--- a Generic instance for your datatype.-gflabels :: forall t . (Generic (t (Const Text)),-                        GLabels (Rep (t (Const Text)) ()))-         => t (Const Text)-gflabels = to (genFlabels :: Rep (t (Const Text)) ())-     data Dict c (t :: k) where-  -- | reified type class dictionary.  You need to put the constructor-  -- in scope in order to use the contained typeclass dictionaries.+  -- | reified type class dictionary. You can use the contained+  -- typeclass by putting the `Dict` constructor somewhere within+  -- scope. Can be auto derived with a Generic instance.   Dict :: c t => Dict c t  class FDicts c t where   -- | hkd record containing the reified type class dictionaries for-  -- each field.+  -- each field.  This allows you to use functions with constraints by+  -- combining `fdicts` with `fzipWith` or `fzipManyWith`.  Can be+  -- auto derived with a Generic instance.+  default fdicts :: (Generic (t (Dict c)),+                     GFDicts (Rep (t (Dict c)) ()))+                 => t (Dict c)+  fdicts = to (genFdict :: Rep (t (Dict c)) ())   fdicts :: t (Dict c)  class GFDicts t where@@ -92,22 +130,15 @@   genFdict = M1 $ M1 $ genFdict   {-# INLINE genFdict #-} --- | Automatically derive fdict using generics.  This only requires a--- Generic instance for your datatype.-gfdicts :: forall t c . (Generic (t (Dict c)),-                        GFDicts (Rep (t (Dict c)) ()))-         => t (Dict c)-gfdicts = to (genFdict :: Rep (t (Dict c)) ())- infixr 5 :> infixr 5 :~>  -- | A heterogenous list of higher kinded records.  Use `:~>` to -- separate the items, and `End` to terminate them.-data HkdProd (f :: a -> *) g t = t f :~> g t+data RecordCons (f :: a -> *) g t = t f :~> g t -- | A heterogenous list of fields.  Use `:>` to separate the items, -- and `End` to terminate them.-data LkdProd f g (x :: a) = f x :> g x+data FieldCons f g (x :: a) = f x :> g x -- | The terminator. data End (t :: k) = End @@ -118,7 +149,7 @@   gftranspose End = frepeat End  instance (FZip t, GFTranspose g t g') => -  GFTranspose (HkdProd f g) t (LkdProd f g') where+  GFTranspose (RecordCons f g) t (FieldCons f g') where   gftranspose (tf :~> tg) = fzipWith (:>) tf $ gftranspose tg  -- | zip over many arguments.  The function must take a heterogenous@@ -129,16 +160,10 @@ -- For example: -- -- @--- zipShow :: (FFoldable t, FRepeat t, FLabels t, FDicts Show t, FZip t) =>---            t Identity -> Text--- zipShow t =---   Text.concat $---   intersperse "&" $---   ftoList $  --   fzipManyWith --   (\(Identity y :> Const lbl :> Dict :> End) -> --       Const $ lbl <> "=" <> Text.pack (show y))---   (t :~> flabels :~> fdicts @Show :~> End)+--   (t :~> fieldNames :~> fdicts @Show :~> End) -- @  fzipManyWith :: ( FFunctor t, GFTranspose x t f) =>@@ -164,16 +189,22 @@ compIsoFLens wrap unwrap = compFLens (iso wrap unwrap) {-# INLINE compIsoFLens #-} -class FLenses t where-  -- A record of lenses into the record.+class FLenses (t :: (k -> *) -> *) where+  -- A record of lenses into the record.  Can be auto derived with a+  -- Generic instance.+  default flenses :: forall r g . GFlensesMachinery k t r g+                  => t (FLens g t)+  flenses = ffmap (compIsoFLens toHkd fromHkd) $+            toHkd (genflenses @(Rep (t g)) @k @r)+  {-# INLINE flenses #-}   flenses :: t (FLens g t)  -- newtype to get rid of the extra type variable newtype Tupled f (a :: k) = Tupled {unTupled :: f a ()}  -- these newtypes just rearrange the type variables so they -newtype FunctorS1 label _x _x2 _x3 a g k =-  FunctorS1 { getFunctorS1 :: (S1 ('MetaSel label _x _x2 _x3)+newtype FunctorS1 fieldName _x _x2 _x3 a g k =+  FunctorS1 { getFunctorS1 :: (S1 ('MetaSel fieldName _x _x2 _x3)                                (Rec0 (g a))                                k)} @@ -182,7 +213,7 @@  newtype FunctorProd f g a k = FunctorProd ((f a :*: g a) k) -instance FFunctor (Tupled (FunctorS1 label _x _x2 _x3 a)) where+instance FFunctor (Tupled (FunctorS1 fieldName _x _x2 _x3 a)) where   ffmap f (Tupled (FunctorS1 (M1 (K1 x))))     = Tupled $ FunctorS1 $ M1 $ K1 $ f x   {-# INLINE ffmap #-}@@ -207,10 +238,10 @@   GFLenses (x :: * -> *) k (r :: (k -> *) -> * -> *) g | x -> k, x -> r where   genflenses :: Tupled r (FLens g (Tupled r))   -instance GFLenses ((S1 ('MetaSel label _x _x2 _x3)+instance GFLenses ((S1 ('MetaSel fieldName _x _x2 _x3)                     (Rec0 (g (a :: k))) :: * -> *))                    k-                  (FunctorS1 label _x _x2 _x3 a)+                  (FunctorS1 fieldName _x _x2 _x3 a)                   g where   genflenses = Tupled $ FunctorS1 $ M1 $ K1 $ FLens $ \f g ->     ( Tupled . FunctorS1  . M1 . K1 ) <$>@@ -262,14 +293,6 @@   , GFLenses (Rep (t g)) k (r :: (k -> *) -> * -> *) g   ) --- | Autogenerate lenses using generics.  You only need to derive--- Generic for the datatype.-gflenses :: forall k t r g . GFlensesMachinery k t r g-         => t (FLens g t)-gflenses = ffmap (compIsoFLens toHkd fromHkd) $-           toHkd (genflenses @(Rep (t g)) @k @r)-{-# INLINE gflenses #-}- toHkd :: forall t g r.          ( Generic (t g)          , Coercible (r g ()) (Rep (t g) ())@@ -286,7 +309,7 @@ fromHkd r = coerce (from r :: Rep (t g) ()) {-# INLINE fromHkd #-} --- | collect (Const) elements into a list efficiently.+-- | collect `Const` elements into a list efficiently. ftoList :: FFoldable t => t (Const a) -> [a] ftoList = flip appEndo [] . ffoldMap (Endo . (:) . getConst)