packages feed

prolens 0.0.0.0 → 0.0.0.1

raw patch · 6 files changed

+171/−53 lines, 6 filesdep ~basedep ~doctestPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base, doctest

API changes (from Hackage documentation)

- Prolens: instance GHC.Base.Monoid r => Prolens.Choice (Prolens.Forget r)
- Prolens: instance GHC.Base.Monoid r => Prolens.Monoidal (Prolens.Forget r)
+ Prolens: instance Prolens.Choice (Prolens.Forget r)
+ Prolens: instance Prolens.Monoidal (Prolens.Forget r)
- Prolens: Forget :: (a -> r) -> Forget r a b
+ Prolens: Forget :: (a -> Maybe r) -> Forget r a b
- Prolens: [unForget] :: Forget r a b -> a -> r
+ Prolens: [unForget] :: Forget r a b -> a -> Maybe r
- Prolens: preview :: forall a source p. p ~ Forget (First a) => Optic p source source a a -> source -> Maybe a
+ Prolens: preview :: forall a source p. p ~ Forget a => Optic p source source a a -> source -> Maybe a

Files

CHANGELOG.md view
@@ -3,6 +3,22 @@ `prolens` uses [PVP Versioning][1]. The changelog is available [on GitHub][2]. +## 👩‍👧 0.0.0.1 — Mar 14, 2021++* [#51](https://github.com/kowainik/prolens/issues/51):+  Support GHC 9.0. Upgrade minor versions support to 8.10.4.+* [#28](https://github.com/kowainik/prolens/issues/28):+  Inspection tests for prisms, ensuring optimal performance.+* [#46](https://github.com/kowainik/prolens/issues/46):+  Document typeclasses laws.+* [#7](https://github.com/kowainik/prolens/issues/7):+  Add typeclasses laws tests for the following types:++    + `Profunctor` laws for `Forget`+    + `Monoidal` laws for `(->)`++Thanks @CristhianMotoche, @xplosunn for helping with this release!+ ## 0.0.0.0  * Initially created.
prolens.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.4 name:                prolens-version:             0.0.0.0+version:             0.0.0.1 synopsis:            Profunctor-based lightweight implementation of optics description:     Lightweight and performance implementation of optics — lenses, prisms, traversals.@@ -14,21 +14,22 @@ license-file:        LICENSE author:              Veronika Romashkina, Dmitrii Kovanikov maintainer:          Kowainik <xrom.xkov@gmail.com>-copyright:           2020 Kowainik+copyright:           2020-2021 Kowainik category:            Data, Optics, Lenses build-type:          Simple extra-doc-files:     README.md                      CHANGELOG.md tested-with:         GHC == 8.6.5                      GHC == 8.8.4-                     GHC == 8.10.2+                     GHC == 8.10.4+                     GHC == 9.0.1  source-repository head   type:                git   location:            https://github.com/kowainik/prolens.git  common common-options-  build-depends:       base >= 4.12.0.0 && < 4.15+  build-depends:       base >= 4.12.0.0 && < 4.16    ghc-options:         -Wall                        -Wcompat@@ -96,4 +97,4 @@   import:              common-test   type:                exitcode-stdio-1.0   main-is:             Doctest.hs-  build-depends:       doctest ^>= 0.17+  build-depends:       doctest >= 0.16.3 && < 0.19
src/Prolens.hs view
@@ -5,9 +5,12 @@ {-# LANGUAGE TypeFamilies          #-}  {- |-Copyright: (c) 2020 Kowainik-SPDX-License-Identifier: MPL-2.0-Maintainer: Kowainik <xrom.xkov@gmail.com>+Module                  : Prolens+Copyright               : (c) 2020-2021 Kowainik+SPDX-License-Identifier : MPL-2.0+Maintainer              : Kowainik <xrom.xkov@gmail.com>+Stability               : Stable+Portability             : Portable  The @prolens@ package is a Haskell library with a minimal and lightweight implementation of optics based on 'Profunctor's. __'Optic'__ is a high-level@@ -148,6 +151,7 @@ import Data.Coerce (coerce) import Data.Monoid (First (..)) + -- $setup -- >>> import Data.Function ((&)) @@ -194,7 +198,7 @@ Instances of 'Profunctor' should satisfy the following laws:  * __Identity:__ @'dimap' 'id' 'id' ≡ 'id'@-* __Composition:__ @'dimap' (inAB . inBC) (outYZ . outXY) ≡ 'dimap' outBC outYZ . 'dimap' outAB outXY@+* __Composition:__ @'dimap' (inAB . inBC) (outYZ . outXY) ≡ 'dimap' inBC outYZ . 'dimap' inAB outXY@  @since 0.0.0.0 -}@@ -239,6 +243,20 @@ type, and you can decide what type it should be. This is convenient for implementing various functions. E.g. 'lens' uses this fact. +Instances of 'Strong' should satisfy the following laws:++* __'first' via 'second' swap:__ @'first' ≡ 'dimap' 'Data.Tuple.swap' 'Data.Tuple.swap' . 'second'@+* __'second' via 'first' swap:__ @'second' ≡ 'dimap' 'Data.Tuple.swap' 'Data.Tuple.swap' . 'first'@++* __Fst functor:__ @'dimap' 'fst' 'id' ≡ 'fmap' 'fst' . 'first'@+* __Snd functor:__ @'dimap' 'snd' 'id' ≡ 'fmap' 'snd' . 'second'@++* __Distribution over 'first':__ @'dimap' ('second' f) 'id' . 'first' ≡ 'fmap' ('second' f) . 'first'@+* __Distribution over 'second':__ @'dimap' ('first' f) 'id' . 'second' ≡ 'fmap' ('first' f) . 'second'@++* __Associativity of 'first':__ @'first' . 'first' ≡ 'dimap' (\\((a, b), c) -> (a, (b, c))) (\\(a, (b, c)) -> ((a, b), c)) . 'first'@+* __Associativity of 'second':__ @'second' . 'second' ≡ 'dimap' (\\(a, (b, c)) -> ((a, b), c)) (\\((a, b), c) -> (a, (b, c))) . 'second'@+ @since 0.0.0.0 -} class Profunctor p => Strong p where@@ -272,6 +290,29 @@ type, and you can decide what type it should be. This is convenient for implementing various functions. E.g. 'prism' uses this fact. ++Assuming, we have the following functions in scope:++@+swapEither  :: Either a b -> Either b a+unnestLeft  :: Either (Either a b) c -> Either a (Either b c)+unnestRight :: Either a (Either b c) -> Either (Either a b) c+@++Instances of 'Choice' should satisfy the following laws:++* __'left' via 'right' swap:__ @'left' ≡ 'dimap' swapEither swapEither . 'right'@+* __'right' via 'left' swap:__ @'right' ≡ 'dimap' swapEither swapEither . 'left'@++* __'Left' functor:__ @'fmap' 'Left' ≡ 'dimap' 'Left' 'id' . 'left'@+* __'Right' functor:__ @'fmap' 'Right' ≡ 'dimap' 'Right' 'id' . 'right'@++* __Distribution over 'left':__ @'dimap' ('right' f) 'id' . 'left' ≡ 'fmap' ('right' f) . 'left'@+* __Distribution over 'right':__ @'dimap' ('left' f) 'id' . 'right' ≡ 'fmap' ('left' f) . 'right'@++* __Associativity of 'left':__ @'left' . 'left' ≡ 'dimap' unnestLeft unnestRight . 'left'@+* __Associativity of 'right':__ @'right' . 'right' ≡ 'dimap' unnestRight unnestLeft . 'right'@+ @since 0.0.0.0 -} class Profunctor p => Choice p where@@ -309,11 +350,27 @@ {- | 'Monoidal' is 'Strong' 'Profunctor' that can be appended. It is similar to 'Monoid's but for higher-kinded types. +Instances of 'Monoidal' should satisfy the following laws:++* __Right identity:__ @'pappend' f 'pempty' ≡ 'first' f@+* __Left identity:__ @'pappend' 'pempty' f ≡ 'second' f@+* __Associativity:__ @'pappend' f ('pappend' g h) ⋍ 'pappend' ('pappend' f g) h@++⚠️ __Note:__ The @⋍@ operator in the __associativity__ law is equality+ignoring the structure. The law is written in that way because+'pappend' returns a tuple and the order of nested tuples depends on+the order of 'pappend' applications. In practice, this means, that if+you want to check the law, you reorder tuples in the following way:++@+'pappend' f ('pappend' g h) ≡ 'dimap' (\\(a, (b, c)) -> ((a, b), c)) (\\((a, b), c) -> (a, (b, c))) ('pappend' ('pappend' f g) h)+@+ @since 0.0.0.0 -} class Strong p => Monoidal p where     pappend :: p a b -> p c d -> p (a, c) (b, d)-    pempty :: p a a+    pempty  :: p a a  -- | @since 0.0.0.0 instance Monoidal (->) where@@ -574,7 +631,7 @@ -} infixr 4 .~ (.~) :: Lens' source a -> a -> source -> source-(.~) = set+(.~) l = set l {-# INLINE (.~) #-}  {- | The operator form of 'over'.@@ -583,7 +640,7 @@ -} infixr 4 %~ (%~) :: Lens' source a -> (a -> a) -> source -> source-(%~) = over+(%~) l = over l {-# INLINE (%~) #-}  {- | 'Lens'' for a tuple on the first argument.@@ -750,13 +807,14 @@ @since 0.0.0.0 -} newtype Forget r a b = Forget-    { unForget :: a -> r+    { unForget :: a -> Maybe r     }  -- | @since 0.0.0.0 instance Functor (Forget r x) where     fmap :: (a -> b) -> Forget r x a -> Forget r x b     fmap _ = coerce+    {-# INLINE fmap #-}  -- | @since 0.0.0.0 instance Profunctor (Forget r) where@@ -775,23 +833,24 @@     {-# INLINE second #-}  -- | @since 0.0.0.0-instance Monoid r => Choice (Forget r) where+instance Choice (Forget r) where     left :: Forget r a b -> Forget r (Either a c) (Either b c)-    left (Forget ar) = Forget (either ar (const mempty))+    left (Forget ar) = Forget (either ar (const Nothing))     {-# INLINE left #-}      right :: Forget r a b -> Forget r (Either c a) (Either c b)-    right (Forget ar) = Forget (either (const mempty) ar)+    right (Forget ar) = Forget (either (const Nothing) ar)     {-# INLINE right #-}  -- | @since 0.0.0.0-instance (Monoid r) => Monoidal (Forget r) where+instance Monoidal (Forget r) where     pappend :: Forget r a b -> Forget r c d -> Forget r (a, c) (b, d)-    pappend (Forget ar) (Forget cr) = Forget (\(a, c) -> ar a <> cr c)+    pappend (Forget ar) (Forget cr) = Forget+        (\(a, c) -> getFirst $  First (ar a) <> First (cr c))     {-# INLINE pappend #-}      pempty :: Forget r a a-    pempty = Forget (const mempty)+    pempty = Forget (const Nothing)     {-# INLINE pempty #-}  {- | Match a value from @source@ type.@@ -800,14 +859,14 @@ -} preview     :: forall a source p-    .  (p ~ Forget (First a))+    .  (p ~ Forget a)     => Optic p source source a a  -- ^ 'Optic' that can be prism     -> source  -- ^ Object (possible sum type)     -> Maybe a  -- ^ Value of type @a@ from a specific constructor preview paapss = coerce (paapss wrap)   where-    wrap :: Forget (First a) a a-    wrap = coerce @(a -> Maybe a) @(Forget (First a) a a) Just+    wrap :: Forget a a a+    wrap = coerce @(a -> Maybe a) @(Forget a a a) Just     {-# INLINE wrap #-} {-# INLINE preview #-} -- preview paapss = getFirst . unForget (paapss (Forget (First . Just)))
test/Test/Data.hs view
@@ -19,6 +19,7 @@       -- * Generators     , genFun     , genFunction+    , genForget     , genHaskeller     , genInt     , genKnowledge@@ -27,7 +28,7 @@  import Test.Hspec.Hedgehog (MonadGen) -import Prolens (Fun (..), Lens', Prism', lens, prism')+import Prolens (Forget (..), Fun (..), Lens', Prism', lens, prism')  import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range@@ -129,3 +130,6 @@     , const Nothing     , Just . f     ]++genForget :: MonadGen m => m (Forget Int Int a)+genForget = Forget . unFun <$> genFun
test/Test/Prolens/Inspection.hs view
@@ -9,7 +9,7 @@     ( inspectionSpecs     ) where -import Test.Hspec (Spec, describe, it, shouldSatisfy, xit)+import Test.Hspec (Spec, describe, it, shouldSatisfy) import Test.Inspection (Result (..), hasNoTypeClasses, inspectTest, (===))  import Prolens (preview, set, view)@@ -77,7 +77,7 @@ prismSpecs :: Spec prismSpecs = describe "Prism" $ do     describe "preview" $ do-        xit "preview _Ctor x ≡ case (Ctor _) of" $+        it "preview _Ctor x ≡ case (Ctor _) of" $             $(inspectTest $ 'matchMarkPrism === 'matchMarkManual) `shouldSatisfy` isSuccess  -- Helper functions
test/Test/Prolens/Property.hs view
@@ -3,11 +3,12 @@     , typeclassesPropertySpecs     ) where +import Hedgehog (Gen) import Test.Hspec (Spec, describe, it) import Test.Hspec.Hedgehog (PropertyT, forAll, forAllWith, hedgehog, (===))  import Prolens-import Test.Data (genFun, genFunction, genHaskeller, genInt, genName, nameL)+import Test.Data (genFun, genFunction, genForget, genHaskeller, genInt, genName, nameL)   lensPropertySpecs :: Spec@@ -26,43 +27,80 @@         set nameL valueNew (set nameL value source) === set nameL valueNew source  typeclassesPropertySpecs :: Spec-typeclassesPropertySpecs = describe "Class Laws" -- $ do+typeclassesPropertySpecs = describe "Class Laws" $ do     profunctorsSpec+    monoidalSpec  profunctorsSpec :: Spec profunctorsSpec = describe "Profunctor" $ do-    describe "(->)" $ do-        it "Identity: dimap id id ≡ id" $ hedgehog $ do-            f <- forAllWith (const "f") genFunction-            x <- forAll genInt-            dimap id id f x === f x-        it "Composition: dimap (ab . bc) (yz . xy) ≡ dimap bc yz . dimap ab xy" $ hedgehog $ do+    profunctorLaws "(->)" genFunction eqFunction+    profunctorLaws "Fun" genFun eqFun+    profunctorLaws "Forget" genForget eqForget -            f  <- forAllWith (const "f")  genFunction-            ab <- forAllWith (const "ab") genFunction-            bc <- forAllWith (const "bc") genFunction-            xy <- forAllWith (const "xy") genFunction-            yz <- forAllWith (const "xy") genFunction -            n <- forAll genInt-            dimap (ab . bc) (yz . xy) f n === (dimap bc yz . dimap ab xy) f n-    describe "Fun" $ do-        it "Identity: dimap id id ≡ id" $ hedgehog $ do-            f <- forAllWith (const "f") genFun-            eqFun (dimap id id f) f-        it "Composition: dimap (ab . bc) (yz . xy) ≡ dimap bc yz . dimap ab xy" $ hedgehog $ do+profunctorLaws+  :: Profunctor p+  => String+  -> Gen (p Int Int)+  -> (p Int Int -> p Int Int -> PropertyT IO ())+  -> Spec+profunctorLaws name genProfunctor cmp =+  describe name $ do+    it "Identity: dimap id id ≡ id" $ hedgehog $ do+        f <- forAllWith (const "f") genProfunctor+        dimap id id f `cmp` f -            f  <- forAllWith (const "f")  genFun-            ab <- forAllWith (const "ab") genFunction-            bc <- forAllWith (const "bc") genFunction-            xy <- forAllWith (const "xy") genFunction-            yz <- forAllWith (const "xy") genFunction+    it "Composition: dimap (ab . bc) (yz . xy) ≡ dimap bc yz . dimap ab xy" $ hedgehog $ do+        f  <- forAllWith (const "f")  genProfunctor+        ab <- forAllWith (const "ab") genFunction+        bc <- forAllWith (const "bc") genFunction+        xy <- forAllWith (const "xy") genFunction+        yz <- forAllWith (const "xy") genFunction -            eqFun-                (dimap (ab . bc) (yz . xy) f)-                (dimap bc yz $ dimap ab xy f)+        dimap (ab . bc) (yz . xy) f `cmp` (dimap bc yz . dimap ab xy) f ++eqFunction :: (Int -> Int) -> (Int -> Int) -> PropertyT IO ()+eqFunction f g = do+    n <- forAll genInt+    f n === g n+ eqFun :: Fun Maybe Int Int -> Fun Maybe Int Int -> PropertyT IO () eqFun fun1 fun2 = do     x <- forAll genInt     unFun fun1 x === unFun fun2 x++eqForget :: Forget Int Int a -> Forget Int Int a -> PropertyT IO ()+eqForget forget1 forget2 = do+    x <- forAll genInt+    unForget forget1 x === unForget forget2 x+    +monoidalSpec :: Spec+monoidalSpec = describe "Monoidal" $ do+    describe "(->)" $ do+        it "Identity: pappend f pempty ≡ first f" $ hedgehog $ do+            f <- forAllWith (const "f") genFunction+            x <- forAll genInt+            y <- forAll genInt+            pappend f pempty (x, y) === first f (x, y)+        it "Identity: pappend pempty f ≡ second f" $ hedgehog $ do+            f <- forAllWith (const "f") genFunction+            x <- forAll genInt+            y <- forAll genInt+            pappend pempty f (x, y) === second f (x, y)+        it "Associativity (right)" $ hedgehog $ do+            f <- forAllWith (const "f") genFunction+            g <- forAllWith (const "g") genFunction+            h <- forAllWith (const "h") genFunction+            x <- forAll genInt+            y <- forAll genInt+            z <- forAll genInt+            pappend f (pappend g h) (x, (y, z)) === (f x, (g y, h z))+        it "Associativity (left)" $ hedgehog $ do+            f <- forAllWith (const "f") genFunction+            g <- forAllWith (const "g") genFunction+            h <- forAllWith (const "h") genFunction+            x <- forAll genInt+            y <- forAll genInt+            z <- forAll genInt+            pappend (pappend f g) h ((x, y), z) === ((f x, g y), h z)