packages feed

higgledy 0.1.1.0 → 0.1.1.1

raw patch · 6 files changed

+158/−39 lines, 6 filesdep ~QuickCheckdep ~barbiesdep ~basePVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

Dependency ranges changed: QuickCheck, barbies, base, generic-lens, hspec

API changes (from Hackage documentation)

+ Data.Generic.HKD.Build: build :: Build structure f k => k
+ Data.Generic.HKD.Build: class Build (structure :: Type) (f :: Type -> Type) (k :: Type) | f structure -> k
+ Data.Generic.HKD.Build: instance (Data.Generic.HKD.Build.Fill f structure xs, Data.Generic.HKD.Build.GBuild f structure xs k) => Data.Generic.HKD.Build.Build structure f k
+ Data.Generic.HKD.Build: instance (Data.Generic.HKD.Build.GFill f xs ys left, Data.Generic.HKD.Build.GFill f ys zs right) => Data.Generic.HKD.Build.GFill f xs zs (left GHC.Generics.:*: right)
+ Data.Generic.HKD.Build: instance (GHC.Generics.Generic shape, Data.Generic.HKD.Build.GFill f with '[] (GHC.Generics.Rep shape)) => Data.Generic.HKD.Build.Fill f shape with
+ Data.Generic.HKD.Build: instance Data.Generic.HKD.Build.GBuild f structure '[] (Data.Generic.HKD.Types.HKD structure f)
+ Data.Generic.HKD.Build: instance Data.Generic.HKD.Build.GBuild f structure xs k => Data.Generic.HKD.Build.GBuild f structure (x : xs) (x -> k)
+ Data.Generic.HKD.Build: instance Data.Generic.HKD.Build.GFill f (f x : xs) xs (GHC.Generics.Rec0 x)
+ Data.Generic.HKD.Build: instance Data.Generic.HKD.Build.GFill f xs ys inner => Data.Generic.HKD.Build.GFill f xs ys (GHC.Generics.M1 index meta inner)

Files

README.md view
@@ -53,6 +53,8 @@ module Example where  import Control.Lens ((.~), (^.), (&), Const (..), Identity, anyOf)+import Data.Funtor.Const (Const (..))+import Data.Funtor.Identity (Identity (..)) import Data.Generic.HKD import Data.Maybe (isJust, isNothing) import Data.Monoid (Last (..))@@ -163,14 +165,27 @@ -- Last {getLast = Just (Triple 123 () "ABC")} ``` +If none of the above suit your needs, maybe you want to try `build` on for+size. This function constructs an `HKD`-wrapped version of the type supplied to+it by taking all its parameters. In other words:++```haskell+eg6 :: f Int -> f () -> f String -> HKD Triple f+eg6 = build @Triple++eg7 :: HKD Triple []+eg7 = eg6 [1] [] ["Tom", "Tim"]+-- Triple [1] [] ["Tom","Tim"]+```+ ### Field Access  The `field` lens, when given a type-applied field name, allows us to focus on fields within a record:  ```haskell-eg6 :: Last Int-eg6 = eg0 ^. field @"age"+eg8 :: Last Int+eg8 = eg0 ^. field @"age" -- Last {getLast = Nothing} ``` @@ -179,8 +194,8 @@ choice):  ```haskell-eg7 :: Partial User-eg7 = eg0 & field @"name"      .~ pure "Evil Tom"+eg9 :: Partial User+eg9 = eg0 & field @"name"      .~ pure "Evil Tom"           & field @"likesDogs" .~ pure False      -- User --   { name      = Last {getLast = Just "Evil Tom"}@@ -193,8 +208,8 @@ completed for a given partial type:  ```haskell-eg8 :: Bool-eg8 = anyOf (field @"name") (isJust . getLast) eg0+eg10 :: Bool+eg10 = anyOf (field @"name") (isJust . getLast) eg0 -- False ``` @@ -203,8 +218,8 @@ doesn't exist in our type:  ```haskell-eg9 :: Identity ()-eg9 = eg3 ^. field @"oops"+eg11 :: Identity ()+eg11 = eg3 ^. field @"oops" -- error: -- • The type User does not contain a field named 'oops'. ```@@ -215,8 +230,8 @@ product types:  ```haskell-eg10 :: Labels Triple-eg10 = mempty & position @1 .~ Const "hello"+eg12 :: Labels Triple+eg12 = mempty & position @1 .~ Const "hello"               & position @2 .~ Const "world" -- Triple --   Const "hello"@@ -227,8 +242,8 @@ Again, this is a `Lens`, so we can just as easily _set_ values:  ```haskell-eg11 :: Partial User-eg11 = eg7 & position @2 .~ pure 25+eg13 :: Partial User+eg13 = eg9 & position @2 .~ pure 25 -- User --   { name      = Last {getLast = Just "Evil Tom"} --   , age       = Last {getLast = Just 25}@@ -240,8 +255,8 @@ type errors are a delight:  ```haskell-eg9 :: Identity ()-eg9 = deconstruct @Identity triple ^. position @4+eg14 :: Identity ()+eg14 = deconstruct @Identity triple ^. position @4 -- error: -- • The type Triple does not contain a field at position 4 ```@@ -253,8 +268,8 @@ this interface:  ```haskell-eg10 :: Labels User-eg10 = label eg11+eg15 :: Labels User+eg15 = label eg13 -- User --   { name = Const "name" --   , age = Const "age"@@ -269,7 +284,7 @@ fields whose values satisfy some predicate:  ```haskell-eg13 :: [String]-eg13 = labelsWhere (isNothing . getLast) eg7+eg16 :: [String]+eg16 = labelsWhere (isNothing . getLast) eg9 -- ["age"] ```
higgledy.cabal view
@@ -1,7 +1,7 @@ cabal-version:       2.4  name:                higgledy-version:             0.1.1.0+version:             0.1.1.1 synopsis:            Partial types as a type constructor. description:         Use the generic representation of an ADT to get a higher-kinded data-style interface automatically. homepage:            https://github.com/i-am-tom/higgledy@@ -17,6 +17,7 @@  library   exposed-modules:     Data.Generic.HKD+                       Data.Generic.HKD.Build                        Data.Generic.HKD.Construction                        Data.Generic.HKD.Field                        Data.Generic.HKD.Labels@@ -24,20 +25,20 @@                        Data.Generic.HKD.Types   -- other-modules:   -- other-extensions:-  build-depends:       base ^>=4.12.0.0-                     , barbies ^>=1.1.0.0-                     , generic-lens ^>=1.1.0.0-                     , QuickCheck ^>=2.13.0+  build-depends:       base ^>=4.12+                     , barbies ^>=1.1.0+                     , generic-lens ^>=1.1.0+                     , QuickCheck ^>=2.12.6   hs-source-dirs:      src   default-language:    Haskell2010  test-suite test-  build-depends:       base+  build-depends:       base ^>=4.12                      , doctest ^>=0.16.0                      , higgledy-                     , hspec ^>=2.7.0+                     , hspec ^>=2.6.1                      , lens ^>=4.17-                     , QuickCheck+                     , QuickCheck ^>= 2.12.6   main-is:             Main.hs   type:                exitcode-stdio-1.0   hs-source-dirs:      test
src/Data/Generic/HKD.hs view
@@ -10,6 +10,7 @@   ( module Exports   ) where +import Data.Generic.HKD.Build        as Exports import Data.Generic.HKD.Construction as Exports import Data.Generic.HKD.Field        as Exports import Data.Generic.HKD.Labels       as Exports
+ src/Data/Generic/HKD/Build.hs view
@@ -0,0 +1,107 @@+{-# OPTIONS_HADDOCK not-home #-}++{-# LANGUAGE AllowAmbiguousTypes    #-}+{-# LANGUAGE BlockArguments         #-}+{-# LANGUAGE DataKinds              #-}+{-# LANGUAGE FlexibleInstances      #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE GADTs                  #-}+{-# LANGUAGE PolyKinds              #-}+{-# LANGUAGE ScopedTypeVariables    #-}+{-# LANGUAGE TypeApplications       #-}+{-# LANGUAGE TypeOperators          #-}+{-# LANGUAGE UndecidableInstances   #-}++{-|+Module      : Data.Generic.HKD.Build+Description : Construct an HKD structure with its component parameters.+Copyright   : (c) Tom Harding, 2019+License     : MIT+Maintainer  : tom.harding@habito.com+Stability   : experimental+-}+module Data.Generic.HKD.Build+  ( Build (..)+  ) where++import Data.Kind (Type)+import Data.GenericLens.Internal (HList (..))+import Data.Generic.HKD.Types (HKD (..), GHKD_)+import GHC.Generics+import Prelude hiding (uncurry)++class Fill (f :: Type -> Type) (structure :: Type) (types :: [Type])+    | structure f -> types, types -> f where+  fill :: HList types -> HKD structure f++class GFill (f :: Type -> Type) (xs :: [Type]) (ys :: [Type]) (rep :: Type -> Type)+    | xs rep -> ys, ys f rep -> xs, xs -> f where+  gfill :: HList xs -> (HList ys, GHKD_ f rep p)++instance GFill f xs ys inner+    => GFill f xs ys (M1 index meta inner) where+  gfill = fmap M1 . gfill @f++instance (GFill f xs ys left, GFill f ys zs right)+    => GFill f xs zs (left :*: right) where+  gfill xs = do+    let (ys,  left) = gfill @f xs+        (zs, right) = gfill @f ys++    (zs, left :*: right)++instance GFill f (f x ': xs) xs (Rec0 x) where+  gfill (x :> xs) = (xs, K1 x)++instance (Generic shape, GFill f with '[] (Rep shape))+    => Fill f shape with where+  fill = HKD . snd . gfill @f @_ @'[]++-- | With many HKD applications, we're working with types like 'Maybe' where it+-- makes sense for us to start with 'mempty' and add values in as we go.+--+-- This isn't always the case, however: if all the component parts of our type+-- are gathered using some 'IO' action, we'd like to construct something like+-- @HKD MyType IO@, and @IO a@ isn't a 'Monoid' for all types @a@. When this+-- happens, we need to pass in our parameters /when/ we build our structure.+--+-- The 'build' function lets us construct our type by passing explicit values+-- for each parameter:+--+-- >>> :set -XDeriveGeneric -XTypeApplications+--+-- >>> :{+-- data User+--   = User { name :: String, age :: Int, likesDogs :: Bool }+--   deriving Generic+-- :}+-- +-- >>> :{+-- test :: _+-- test = build @User+-- :}+-- ...+-- ... • Found type wildcard ‘_’+-- ...     standing for ‘f [Char] -> f Int -> f Bool -> HKD User f’+-- ...+--+-- Once we call the 'build' function, and indicate the type we want to build,+-- we are free to pick whichever 'f' we like and get to work!+class Build (structure :: Type) (f :: Type -> Type) (k :: Type)+    | f structure -> k where+  build :: k++class GBuild (f :: Type -> Type) (structure :: Type) (xs :: [Type]) (k :: Type)+    | f structure xs -> k where+  gbuild :: (HList xs -> HKD structure f) -> k++instance GBuild f structure xs k+    => GBuild f structure (x ': xs) (x -> k) where+  gbuild k x = gbuild @_ @_ @xs \xs -> k (x :> xs)++instance GBuild f structure '[] (HKD structure f) where+  gbuild k = k Nil++instance (Fill f structure xs, GBuild f structure xs k)+    => Build structure f k where+  build = gbuild @f @structure @xs fill
src/Data/Generic/HKD/Position.hs view
@@ -34,7 +34,6 @@ import qualified Data.GenericLens.Internal as G import Data.GenericLens.Internal (type (<?)) import qualified Data.Generics.Internal.VL.Lens as G-import Data.Generics.Internal.Profunctor.Lens (ALens)  -- | Product types /without/ named fields can't be addressed by field name (for -- very obvious reason), so we instead need to address them with their
test/Main.hs view
@@ -12,14 +12,12 @@  import Control.Lens (Lens', (.~), (^.)) import Data.Function ((&), on)-import Data.Functor.Identity (Identity (..)) import Data.Generic.HKD import Data.Monoid (Last (..)) import GHC.Generics import Test.DocTest import Test.Hspec import Test.QuickCheck-import Test.QuickCheck.Arbitrary  type Partial a = HKD a Last type WTF     a = HKD a []@@ -180,16 +178,14 @@  partials = describe "HKD" do   describe "Eq" do-    it "is monotonic with respect to ordering (Partial)"-      $ property \(x :: a) y -> (x <= y) == ((<=) `on` deconstruct @Last) x y+    it "is monotonic with respect to ordering (Partial)" $ property \(x :: a) y ->+      (x <= y) == ((<=) `on` deconstruct @Last) x y -    it "is monotonic with respect to ordering (WTF)"-      $ property \(x :: a) y -> (x <= y) == ((<=) `on` deconstruct @[]) x y+    it "is monotonic with respect to ordering (WTF)" $ property \(x :: a) y ->+      (x <= y) == ((<=) `on` deconstruct @[]) x y -    it "round-trips"-      $ property \(x :: a) ->-          construct (deconstruct @Last x) == pure x+    it "round-trips" $ property \(x :: a) ->+      construct (deconstruct @Last x) == pure x -    it "round-trips"-      $ property \(x :: a) ->-          construct (deconstruct @[] x) == pure x+    it "round-trips" $ property \(x :: a) ->+      construct (deconstruct @[] x) == pure x