packages feed

prairie 0.1.0.0 → 0.1.1.0

raw patch · 6 files changed

+102/−23 lines, 6 filesdep ~template-haskellPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: template-haskell

API changes (from Hackage documentation)

- Prairie.Distributed: Distributed :: (forall x. () => Field rec x -> f x) -> Distributed (f :: Type -> Type) rec
- Prairie.Distributed: instance Prairie.Class.SymbolToField sym rec typ => GHC.Records.HasField sym (Prairie.Distributed.Distributed f rec) (f typ)
- Prairie.Distributed: newtype Distributed (f :: Type -> Type) rec
+ Prairie.Class: Distributed :: (forall x. () => Field rec x -> f x) -> Distributed (f :: Type -> Type) rec
+ Prairie.Class: newtype Distributed (f :: Type -> Type) rec
+ Prairie.Class: sequenceRecordA :: forall m (f :: Type -> Type). (Record rec, Applicative m) => Distributed (Compose m f) rec -> m (Distributed f rec)
+ Prairie.Distributed: instance Prairie.Class.SymbolToField sym rec typ => GHC.Records.HasField sym (Prairie.Class.Distributed f rec) (f typ)
+ Prairie.TH: compatConP' :: Name -> [Pat] -> Pat

Files

ChangeLog.md view
@@ -1,5 +1,12 @@ # Changelog for prairie +## 0.1.1.0++- [#24](https://github.com/parsonsmatt/prairie/pull/24)+    - Introduce `sequenceRecordA`, for monadic tabulation of values, using `Distributed`.+- [#29](https://github.com/parsonsmatt/prairie/pull/29)+    - Bump `template-haskell` bound to 2.25+ ## 0.1.0.0  - [#22](https://github.com/parsonsmatt/prairie/pull/22)
prairie.cabal view
@@ -1,7 +1,7 @@ cabal-version: 1.12  name:           prairie-version:        0.1.0.0+version:        0.1.1.0 description:    Please see the README on GitHub at <https://github.com/parsonsmatt/prairie#readme> homepage:       https://github.com/parsonsmatt/prairie#readme bug-reports:    https://github.com/parsonsmatt/prairie/issues@@ -43,7 +43,7 @@     , containers     , mtl     , semigroupoids-    , template-haskell  >=2.15 && <2.24+    , template-haskell          >=2.15 && <2.25     , text     , foldable1-classes-compat 
src/Prairie/Class.hs view
@@ -19,6 +19,7 @@ import Data.Aeson (FromJSON (..), ToJSON (..), withText) import Data.Constraint (Dict (..)) import Data.Functor.Apply (Apply (..))+import Data.Functor.Compose (Compose) import Data.Functor.Const (Const (..)) import Data.Functor.Identity (Identity (..)) import Data.Kind (Constraint, Type)@@ -30,7 +31,6 @@ import Data.Typeable (Typeable, eqT, (:~:) (..)) import GHC.OverloadedLabels (IsLabel (..)) import GHC.TypeLits (Symbol)- import Prairie.Internal (Lens', set, view)  -- | Instances of this class have a datatype 'Field' which allow you to@@ -88,6 +88,10 @@     -- |  Construct a 'Record' by providing an 'Applicative' action     -- returning a value for each 'Field' on the 'Record'.     --+    -- Valid input functions are written in the "function format" of the record, contrasting+    -- the @f@-wrapped "data format" of its return type: the @rec@ value as though it were+    -- written in Haskell record syntax (that does not support 'Applicative' actions).+    --     -- Example:     --     -- @@@ -111,6 +115,19 @@     -- allows you to use 'Foldable1' and 'NonEmpty'.     tabulateRecordApply :: (Apply m) => (forall ty. Field rec ty -> m ty) -> m rec +    -- | Unwrap one 'Applicative' layer of a stack @m (f ty)@ in "function format".+    -- The resulting @m@-action returns the "function format" in @f@-actions,+    -- which can then be addressed directly later in the @m@ action without needing+    -- to tabulate the entire record right away. This is especially useful when the+    -- inner functor has side-effects worth avoiding, like the concatenating behaviour+    -- of @'Monoid' m => 'Const' m@ or the validation of 'Maybe' and @'Either' e@+    -- when the specific field's @m@ or @'Maybe' ty@/@'Either' e ty@ value is of interest+    -- prior to processing the record entirely through that functor.+    --+    -- @since 0.1.1.0+    sequenceRecordA+        :: (Applicative m) => Distributed (Compose m f) rec -> m (Distributed f rec)+     -- | Assign a 'Text' label for a record 'Field'.     --     -- This allows 'Field's to be converted to 'Text', which is useful for@@ -124,6 +141,26 @@     recordFieldLabel :: Field rec ty -> Text     default recordFieldLabel :: (Show (Field rec ty)) => Field rec ty -> Text     recordFieldLabel = Text.pack . show++-- | A @'Distributed' f rec@ is a 'Record' with fields that are wrapped in+-- the @f@ type constructor.+--+-- The simplest example is the trivial 'Identity' - @'Distributed'+-- 'Identity' rec@ wraps each field in 'Identity', which doesn't do+-- anything.+--+-- But you can also represent a @'Distributed' 'IO' rec@, where each field+-- is an 'IO' action.+--+-- This type is equivalently powerful to the @Higher Kinded Data@ pattern,+-- but significantly more flexible, since you don't need to munge the+-- underlying datatype with the complexity of this.+--+-- You can use @OverloadedRecordDot@ to access fields on this directly, or+-- you can also use 'getRecordFieldDistributed'.+--+-- @since 0.1.0.0+newtype Distributed f rec = Distributed (forall x. Field rec x -> f x)  -- | An enumeration of fields on the record. --
src/Prairie/Distributed.hs view
@@ -28,26 +28,6 @@ import GHC.Records import Prairie.Class --- | A @'Distributed' f rec@ is a 'Record' with fields that are wrapped in--- the @f@ type constructor.------ The simplest example is the trivial 'Identity' - @'Distributed'--- 'Identity' rec@ wraps each field in 'Identity', which doesn't do--- anything.------ But you can also represent a @'Distributed' 'IO' rec@, where each field--- is an 'IO' action.------ This type is equivalently powerful to the @Higher Kinded Data@ pattern,--- but significantly more flexible, since you don't need to munge the--- underlying datatype with the complexity of this.------ You can use @OverloadedRecordDot@ to access fields on this directly, or--- you can also use 'getRecordFieldDistributed'.------ @since 0.1.0.0-newtype Distributed f rec = Distributed (forall x. Field rec x -> f x)- -- |  This instance allows you to use the @OverloadedRecordDot@ with -- distributed records. --
src/Prairie/TH.hs view
@@ -8,6 +8,7 @@ import Data.Char (toLower, toUpper) import Data.Constraint (Dict (..)) import Data.Functor.Apply (Apply (..))+import Data.Functor.Compose import qualified Data.List as List import qualified Data.Text as Text import Data.Traversable (for)@@ -185,6 +186,37 @@                 [ Clause [VarP fromFieldName] (NormalB body) []                 ] +    mkSequenceRecordA <- do+        fromFieldName <- newName "s"+        let+            mkMatch (VarP lamArg) (fieldName, _typ) = do+                let+                    pat = compatConP $ mkConstrFieldName fieldName+                 in+                    Match pat (NormalB (VarE lamArg)) []+        lambda <- do+            vars <- traverse (fmap VarP . newName . nameBase . fst) names'types+            pure $+                LamE+                    vars+                    (ConE 'Distributed `AppE` LamCaseE (List.zipWith mkMatch vars names'types))+        let+            body =+                List.foldl'+                    ( \acc (n, _) ->+                        VarE '(<*>)+                            `AppE` acc+                            `AppE` (VarE 'getCompose `AppE` (VarE fromFieldName `AppE` ConE (mkConstrFieldName n)))+                    )+                    (VarE 'pure `AppE` lambda)+                    names'types++        pure $+            FunD+                'sequenceRecordA+                [ Clause [compatConP' 'Distributed [VarP fromFieldName]] (NormalB body) []+                ]+     mkRecordFieldLabel <- do         fieldName <- newName "fieldName"         body <- pure $@@ -230,6 +262,7 @@                   , recordFieldLensDec                   , mkTabulateRecord                   , mkTabulateRecordApply+                  , mkSequenceRecordA                   , mkRecordFieldLabel                   ]                 )@@ -290,4 +323,13 @@ #else compatConP constrFieldName =     ConP constrFieldName []+#endif++compatConP' :: Name -> [Pat] -> Pat+#if MIN_VERSION_template_haskell(2,18,0)+compatConP' constrFieldName ps =+    ConP constrFieldName [] ps+#else+compatConP' constrFieldName ps  =+    ConP constrFieldName ps  #endif
test/Spec.hs view
@@ -28,6 +28,7 @@ import Control.Monad import Data.Aeson import Data.Functor.Apply (Apply (..))+import Data.Functor.Compose import Data.List.NonEmpty (NonEmpty (..)) import Data.Monoid import Prairie.AsRecord@@ -120,6 +121,18 @@                     { name = "Matt"                     , age = 33                     }++        it "sequenceRecordA" $ do+            Distributed user' <- do+                sequenceRecordA @User @IO @Maybe $ Distributed \case+                    UserName -> Compose do+                        print @Int 10 >> pure (Just "Matt")+                    UserAge -> Compose do+                        print @Int 20 >> pure Nothing+            user' UserName `shouldBe` Just "Matt"+            user' UserAge `shouldBe` Nothing+            tabulateRecordA user' `shouldBe` Nothing+         describe "Fold" $ do             describe "foldRecord" $ do                 it "can count the fields" $ do