pa-label 0.1.0.1 → 0.1.1.0
raw patch · 3 files changed
+116/−14 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Label: unzipT2 :: forall l1 t1 l2 t2. [T2 l1 t1 l2 t2] -> T2 l1 [t1] l2 [t2]
+ Label: unzipT3 :: forall l1 t1 l2 t2 l3 t3. [T3 l1 t1 l2 t2 l3 t3] -> T3 l1 [t1] l2 [t2] l3 [t3]
+ Label: zipT2 :: forall l1 l2 t1 t2. (HasField l1 (T2 l1 [t1] l2 [t2]) [t1], HasField l2 (T2 l1 [t1] l2 [t2]) [t2]) => T2 l1 [t1] l2 [t2] -> [T2 l1 t1 l2 t2]
+ Label: zipT3 :: forall l1 l2 t1 t2 l3 t3. (HasField l1 (T3 l1 [t1] l2 [t2] l3 [t3]) [t1], HasField l2 (T3 l1 [t1] l2 [t2] l3 [t3]) [t2], HasField l3 (T3 l1 [t1] l2 [t2] l3 [t3]) [t3]) => T3 l1 [t1] l2 [t2] l3 [t3] -> [T3 l1 t1 l2 t2 l3 t3]
Files
- CHANGELOG.md +4/−0
- pa-label.cabal +56/−9
- src/Label.hs +56/−5
CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for pa-label +## 0.1.1.0 -- 2024-03-18++* Add `zipT2/zipT3`, `unzipT2/unzipT3`+ ## 0.1.0.0 -- 2023-05-19 * First version; contains the `Label` type, `T2`/`T3`, `E2`/`E3`, and some helpers.
pa-label.cabal view
@@ -1,28 +1,75 @@ cabal-version: 3.0+-- !!! ATTN: file autogenerated from pa-template.cabal.mustache on toplevel !!! name: pa-label-version: 0.1.0.1+version: 0.1.1.0 synopsis: Labels, and labelled tuples and enums (GHC >9.2)-description:+description: license: BSD-3-Clause license-file: LICENSE -- author: maintainer: Philip Patsch <philip.patsch@possehl-analytics.com> copyright: 2023 Possehl Analytics GmbH homepage: https://github.com/possehl-analytics/pa-hackage-category: Data, possehl-analytics+category: Data, Possehl-Analytics build-type: Simple extra-doc-files: CHANGELOG.md README.md -- extra-source-files: -common warnings- ghc-options: -Wall +common common-options+ ghc-options:+ -Wall+ -Wno-type-defaults+ -Wunused-packages+ -Wredundant-constraints+ -fwarn-missing-deriving-strategies++ -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html+ -- for a description of all these extensions+ default-extensions:+ -- Infer Applicative instead of Monad where possible+ ApplicativeDo++ -- Allow literal strings to be Text+ OverloadedStrings++ -- Syntactic sugar improvements+ LambdaCase+ MultiWayIf++ -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error+ NoStarIsType++ -- Convenient and crucial to deal with ambiguous field names, commonly+ -- known as RecordDotSyntax+ OverloadedRecordDot++ -- does not export record fields as functions, use OverloadedRecordDot to access instead+ NoFieldSelectors++ -- Record punning+ RecordWildCards++ -- Improved Deriving+ DerivingStrategies+ DerivingVia++ -- Type-level strings+ DataKinds++ -- to enable the `type` keyword in import lists (ormolu uses this automatically)+ ExplicitNamespaces++ default-language: GHC2021+ library- import: warnings- exposed-modules: Label+ import: common-options+ exposed-modules:+ Label, -- other-modules: -- other-extensions:- build-depends: base <5 hs-source-dirs: src- default-language: GHC2021+ build-depends:+ base <5,+
src/Label.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE LambdaCase #-}-{-# LANGUAGE DerivingStrategies #-} module Label ( -- * Labels@@ -16,9 +15,13 @@ focusOnField, monoMapT2, tupleToT2,+ zipT2,+ unzipT2, T3 (..), monoMapT3, tupleToT3,+ zipT3,+ unzipT3, -- * Named Sums/Enums E2 (..),@@ -91,7 +94,7 @@ getField (Label value) = value -- | Fetch a value from a record, like 'getField', but also keep it wrapped by its label.-getLabel :: forall label record a. HasField label record a => record -> Label label a+getLabel :: forall label record a. (HasField label record a) => record -> Label label a getLabel rec = rec & getField @label & label @label -- | 'fmap' over the contents of the labbelled value. Helper.@@ -99,7 +102,7 @@ mapLabel f (Label a) = Label @label $ f a -- | 'traverse' over the contents of the labbelled value. Helper.-traverseLabel :: forall label f a b. Functor f => (a -> f b) -> Label label a -> f (Label label b)+traverseLabel :: forall label f a b. (Functor f) => (a -> f b) -> Label label a -> f (Label label b) traverseLabel fab (Label a) = Label @label <$> fab a -- | A named 2-element tuple. Since the elements are named, you can access them with `.`.@@ -153,7 +156,7 @@ -- otherwise it cannot infer it. focusOnField :: forall field rec subrec t.- HasField field subrec t =>+ (HasField field subrec t) => (rec -> subrec) -> rec -> T2 field t "dat" rec@@ -169,6 +172,29 @@ tupleToT2 :: forall l1 l2 t1 t2. (t1, t2) -> T2 l1 t1 l2 t2 tupleToT2 (t1, t2) = T2 (label @l1 t1) (label @l2 t2) +-- | If you have a tuple of lists, make it into a list of tuples. The names are attached to each value.+zipT2 ::+ forall l1 l2 t1 t2.+ ( HasField l1 (T2 l1 [t1] l2 [t2]) [t1],+ HasField l2 (T2 l1 [t1] l2 [t2]) [t2]+ ) =>+ T2 l1 [t1] l2 [t2] ->+ [T2 l1 t1 l2 t2]+zipT2 xs =+ zipWith+ (\t1 t2 -> T2 (label @l1 t1) (label @l2 t2))+ (getField @l1 xs)+ (getField @l2 xs)++-- | If you have a list of tuples, make it into a tuple of lists. The names are attached to each value.+unzipT2 :: forall l1 t1 l2 t2. [T2 l1 t1 l2 t2] -> T2 l1 [t1] l2 [t2]+unzipT2 xs = xs <&> toTup & unzip & fromTup+ where+ toTup :: forall a b. T2 a t1 b t2 -> (t1, t2)+ toTup (T2 a b) = (getField @a a, getField @b b)+ fromTup :: (a, b) -> T2 l1 a l2 b+ fromTup (t1, t2) = T2 (label @l1 t1) (label @l2 t2)+ -- | A named 3-element tuple. Since the elements are named, you can access them with `.`. See 'T2' for an example. data T3 (l1 :: Symbol) t1 (l2 :: Symbol) t2 (l3 :: Symbol) t3 = T3 (Label l1 t1) (Label l2 t2) (Label l3 t3) deriving stock (Show, Eq, Ord)@@ -201,6 +227,31 @@ tupleToT3 :: forall l1 l2 l3 t1 t2 t3. (t1, t2, t3) -> T3 l1 t1 l2 t2 l3 t3 tupleToT3 (t1, t2, t3) = T3 (label @l1 t1) (label @l2 t2) (label @l3 t3) +-- | If you have a tuple of lists, make it into a list of tuples. The names are attached to each value.+zipT3 ::+ forall l1 l2 t1 t2 l3 t3.+ ( HasField l1 (T3 l1 [t1] l2 [t2] l3 [t3]) [t1],+ HasField l2 (T3 l1 [t1] l2 [t2] l3 [t3]) [t2],+ HasField l3 (T3 l1 [t1] l2 [t2] l3 [t3]) [t3]+ ) =>+ T3 l1 [t1] l2 [t2] l3 [t3] ->+ [T3 l1 t1 l2 t2 l3 t3]+zipT3 xs =+ zipWith3+ (\t1 t2 t3 -> T3 (label @l1 t1) (label @l2 t2) (label @l3 t3))+ (getField @l1 xs)+ (getField @l2 xs)+ (getField @l3 xs)++-- | If you have a list of tuples, make it into a tuple of lists. The names are attached to each value.+unzipT3 :: forall l1 t1 l2 t2 l3 t3. [T3 l1 t1 l2 t2 l3 t3] -> T3 l1 [t1] l2 [t2] l3 [t3]+unzipT3 xs = xs <&> toTup & unzip3 & fromTup+ where+ toTup :: forall a b c. T3 a t1 b t2 c t3 -> (t1, t2, t3)+ toTup (T3 a b c) = (getField @a a, getField @b b, getField @c c)+ fromTup :: (a, b, c) -> T3 l1 a l2 b l3 c+ fromTup (t1, t2, t3) = T3 (label @l1 t1) (label @l2 t2) (label @l3 t3)+ -- | A named 2-alternative sum (“'Either' with labels”). data E2 (l1 :: Symbol) t1 (l2 :: Symbol) t2 = E21 (Label l1 t1)@@ -259,7 +310,7 @@ & (\(t1s, t2s) -> T2 (label @l1 t1s) (label @l2 t2s)) -- | Map a monadic (actually just a functor-ic) function over each possibility in this enum. All fields have to have the same type.-monoTraverseE2 :: Functor f => (t -> f t') -> E2 l1 t l2 t -> f (E2 l1 t' l2 t')+monoTraverseE2 :: (Functor f) => (t -> f t') -> E2 l1 t l2 t -> f (E2 l1 t' l2 t') monoTraverseE2 f = \case E21 lbl -> lbl & traverseLabel f <&> E21 E22 lbl -> lbl & traverseLabel f <&> E22