lens 5.3.3 → 5.3.4
raw patch · 14 files changed
+156/−44 lines, 14 filesdep ~containers
Dependency ranges changed: containers
Files
- CHANGELOG.markdown +10/−0
- benchmarks/folds.hs +12/−0
- cabal.project +0/−14
- examples/lens-examples.cabal +3/−3
- lens-properties/lens-properties.cabal +1/−1
- lens.cabal +3/−3
- src/Control/Exception/Lens.hs +21/−14
- src/Control/Lens/At.hs +15/−0
- src/Control/Lens/Cons.hs +12/−0
- src/Control/Lens/Each.hs +10/−0
- src/Control/Lens/Empty.hs +14/−0
- src/Control/Lens/Fold.hs +32/−9
- src/Control/Lens/Internal/Iso.hs +8/−0
- src/Control/Lens/Wrapped.hs +15/−0
CHANGELOG.markdown view
@@ -1,3 +1,13 @@+5.3.4 [2025.03.03]+------------------+* Reduce the arity of `foldr1Of`, `foldl1Of`, `foldrOf'`, `foldlOf'`,+ `foldr1Of'`, `foldl1Of'`, `foldrMOf`, and `foldlMOf` so that GHC is more+ eager to inline them. On a simple benchmark involving `sumOf` (defined in+ terms of `foldlOf'`), this improves performance by 8x.+* Add `Ixed`, `Cons`, `Each`, `AsEmpty`, `Reversing`, and `Rewrapped` instances+ for strict boxed vectors when building with `vector-0.13.2` or later.+* Add an `AsEmpty` instance for primitive `Vector`s.+ 5.3.3 [2024.12.28] ------------------ * Add `makeFieldsId`, which generates overloaded field accessors using the
benchmarks/folds.hs view
@@ -31,6 +31,10 @@ [ bench "native" $ nf (V.toList . V.indexed) v , bench "itraversed" $ nf (itoListOf itraversed) v ]+ , bgroup "sum"+ [ bench "native" $ whnf V.sum v+ , bench "each" $ whnf (sumOf each) v+ ] ] , bgroup "unboxed-vector" [ bgroup "toList"@@ -41,6 +45,10 @@ [ bench "native" $ nf (U.toList . U.indexed) u , bench "vTraverse" $ nf (itoListOf vectorTraverse) u ]+ , bgroup "sum"+ [ bench "native" $ whnf U.sum u+ , bench "each" $ whnf (sumOf each) u+ ] ] , bgroup "sequence" [ bgroup "toList"@@ -71,6 +79,10 @@ , bgroup "itoList" [ bench "native" $ nf (zip [(0::Int)..]) l , bench "itraversed" $ nf (itoListOf itraversed) l+ ]+ , bgroup "sum"+ [ bench "native" $ whnf sum l+ , bench "each" $ whnf (sumOf each) l ] ] , bgroup "map"
cabal.project view
@@ -1,17 +1,3 @@ packages: . ./examples ./lens-properties---- TODO: Remove this once the ecosystem has caught up with GHC 9.12-allow-newer:- aeson:ghc-prim,- aeson:template-haskell,- binary-orphans:base,- boring:base,- indexed-traversable:base,- indexed-traversable-instances:base,- integer-conversion:base,- microstache:base,- semialign:base,- these:base,- uuid-types:template-haskell
examples/lens-examples.cabal view
@@ -26,7 +26,7 @@ , GHC == 9.2.8 , GHC == 9.4.8 , GHC == 9.6.6- , GHC == 9.8.2+ , GHC == 9.8.4 , GHC == 9.10.1 , GHC == 9.12.1 @@ -58,11 +58,11 @@ build-depends: base >= 4.5 && < 5,- containers >= 0.4 && < 0.8,+ containers >= 0.4 && < 0.9, gloss >= 1.12 && < 1.14, lens, mtl >= 2.0.1 && < 2.4,- random >= 1.0 && < 1.3,+ random >= 1.0 && < 1.4, streams >= 3.3 && < 4 main-is: Pong.hs default-language: Haskell2010
lens-properties/lens-properties.cabal view
@@ -23,7 +23,7 @@ , GHC == 9.2.8 , GHC == 9.4.8 , GHC == 9.6.6- , GHC == 9.8.2+ , GHC == 9.8.4 , GHC == 9.10.1 , GHC == 9.12.1
lens.cabal view
@@ -1,6 +1,6 @@ name: lens category: Data, Lenses, Generics-version: 5.3.3+version: 5.3.4 license: BSD2 cabal-version: 1.18 license-file: LICENSE@@ -22,7 +22,7 @@ , GHC == 9.2.8 , GHC == 9.4.8 , GHC == 9.6.6- , GHC == 9.8.2+ , GHC == 9.8.4 , GHC == 9.10.1 , GHC == 9.12.1 synopsis: Lenses, Folds and Traversals@@ -183,7 +183,7 @@ bytestring >= 0.10.4.0 && < 0.13, call-stack >= 0.1 && < 0.5, comonad >= 5.0.7 && < 6,- containers >= 0.5.5.1 && < 0.8,+ containers >= 0.5.5.1 && < 0.9, contravariant >= 1.4 && < 2, distributive >= 0.5.1 && < 1, exceptions >= 0.8.2.1 && < 1,
src/Control/Exception/Lens.hs view
@@ -166,11 +166,17 @@ , Bool(..) ) --- $setup--- >>> :set -XNoOverloadedStrings--- >>> import Control.Lens--- >>> import Control.Applicative--- >>> :m + Control.Exception Control.Monad Data.List Prelude+{-+$setup+>>> :set -XNoOverloadedStrings+>>> :set -XScopedTypeVariables+>>> import Control.Lens+>>> import Control.Applicative+>>> :m + Control.Exception Control.Monad Data.List Prelude+#if MIN_VERSION_base(4,20,0)+>>> :m + Control.Exception.Context+#endif+-} ------------------------------------------------------------------------------ -- Exceptions as Prisms@@ -674,19 +680,20 @@ -- @ __AssertionFailed :: Prism' t AssertionFailed - -- | This t'Exception' contains provides information about what assertion failed in the 'String'.- --- -- @- -- '_AssertionFailed' :: 'Prism'' 'AssertionFailed' 'String'- -- '_AssertionFailed' :: 'Prism'' 'SomeException' 'String'- -- @+ {- | This t'Exception' contains provides information about what assertion failed in the 'String'. - {-- TODO: This doctest is temporarily disabled, as it does not work properly on- GHC 9.12. See https://gitlab.haskell.org/ghc/ghc/-/issues/25610.+ @+ '_AssertionFailed' :: 'Prism'' 'AssertionFailed' 'String'+ '_AssertionFailed' :: 'Prism'' 'SomeException' 'String'+ @ +#if MIN_VERSION_base(4,20,0)+ >>> handling exception (\ (ExceptionWithContext ctxt (_ :: AssertionFailed)) -> "caught" <$ guard ("<interactive>" `isInfixOf` displayExceptionContext ctxt) ) $ assert False (return "uncaught")+ "caught"+#else -- >>> handling _AssertionFailed (\ xs -> "caught" <$ guard ("<interactive>" `isInfixOf` xs) ) $ assert False (return "uncaught") -- "caught"+#endif -} _AssertionFailed :: Prism' t String _AssertionFailed = __AssertionFailed._AssertionFailed
src/Control/Lens/At.hs view
@@ -85,6 +85,9 @@ import qualified Data.Vector.Storable as Storable import qualified Data.Vector.Unboxed as Unboxed import Data.Vector.Unboxed (Unbox)+#if MIN_VERSION_vector(0,13,2)+import qualified Data.Vector.Strict as VectorStrict+#endif import Data.Word import Foreign.Storable (Storable) @@ -113,6 +116,9 @@ type instance Index (Prim.Vector a) = Int type instance Index (Storable.Vector a) = Int type instance Index (Unboxed.Vector a) = Int+#if MIN_VERSION_vector(0,13,2)+type instance Index (VectorStrict.Vector a) = Int+#endif type instance Index (Complex a) = Int type instance Index (Identity a) = () type instance Index (Maybe a) = ()@@ -395,6 +401,15 @@ | 0 <= i && i < Unboxed.length v = f (v Unboxed.! i) <&> \a -> v Unboxed.// [(i, a)] | otherwise = pure v {-# INLINE ix #-}++#if MIN_VERSION_vector(0,13,2)+type instance IxValue (VectorStrict.Vector a) = a+instance Ixed (VectorStrict.Vector a) where+ ix i f v+ | 0 <= i && i < VectorStrict.length v = f (v VectorStrict.! i) <&> \a -> v VectorStrict.// [(i, a)]+ | otherwise = pure v+ {-# INLINE ix #-}+#endif type instance IxValue StrictT.Text = Char instance Ixed StrictT.Text where
src/Control/Lens/Cons.hs view
@@ -64,6 +64,9 @@ import qualified Data.Vector.Primitive as Prim import Data.Vector.Unboxed (Unbox) import qualified Data.Vector.Unboxed as Unbox+#if MIN_VERSION_vector(0,13,2)+import qualified Data.Vector.Strict as VectorStrict+#endif import Data.Word import Control.Applicative (ZipList(..)) import Control.Monad.State.Class as State@@ -179,6 +182,15 @@ then Left Unbox.empty else Right (Unbox.unsafeHead v, Unbox.unsafeTail v) {-# INLINE _Cons #-}++#if MIN_VERSION_vector(0,13,2)+instance Cons (VectorStrict.Vector a) (VectorStrict.Vector b) a b where+ _Cons = prism (uncurry VectorStrict.cons) $ \v ->+ if VectorStrict.null v+ then Left VectorStrict.empty+ else Right (VectorStrict.unsafeHead v, VectorStrict.unsafeTail v)+ {-# INLINE _Cons #-}+#endif -- | 'cons' an element onto a container. --
src/Control/Lens/Each.hs view
@@ -54,6 +54,9 @@ import qualified Data.Vector.Storable as Storable import Data.Vector.Storable (Storable) import qualified Data.Vector.Unboxed as Unboxed+#if MIN_VERSION_vector(0,13,2)+import qualified Data.Vector.Strict as VectorStrict+#endif import Data.Vector.Unboxed (Unbox) import Data.Word import qualified Data.Strict as S@@ -194,6 +197,13 @@ instance (Unbox a, Unbox b) => Each (Unboxed.Vector a) (Unboxed.Vector b) a b where each = vectorTraverse {-# INLINE each #-}++#if MIN_VERSION_vector(0,13,2)+-- | @'each' :: 'Traversal' ('Vector.Vector' a) ('Vector.Vector' b) a b@+instance Each (VectorStrict.Vector a) (VectorStrict.Vector b) a b where+ each = vectorTraverse+ {-# INLINE each #-}+#endif -- | @'each' :: 'Traversal' 'StrictT.Text' 'StrictT.Text' 'Char' 'Char'@ instance (a ~ Char, b ~ Char) => Each StrictT.Text StrictT.Text a b where
src/Control/Lens/Empty.hs view
@@ -53,6 +53,10 @@ import qualified Data.Vector.Unboxed as Unboxed import Data.Vector.Unboxed (Unbox) import qualified Data.Vector.Storable as Storable+import qualified Data.Vector.Primitive as Prim+#if MIN_VERSION_vector(0,13,2)+import qualified Data.Vector.Strict as VectorStrict+#endif import Foreign.Storable (Storable) #if !defined(mingw32_HOST_OS) && !defined(ghcjs_HOST_OS)@@ -161,9 +165,19 @@ _Empty = nearly Unboxed.empty Unboxed.null {-# INLINE _Empty #-} +instance Prim.Prim a => AsEmpty (Prim.Vector a) where+ _Empty = nearly Prim.empty Prim.null+ {-# INLINE _Empty #-}+ instance Storable a => AsEmpty (Storable.Vector a) where _Empty = nearly Storable.empty Storable.null {-# INLINE _Empty #-}++#if MIN_VERSION_vector(0,13,2)+instance AsEmpty (VectorStrict.Vector a) where+ _Empty = nearly VectorStrict.empty VectorStrict.null+ {-# INLINE _Empty #-}+#endif instance AsEmpty (Seq.Seq a) where _Empty = nearly Seq.empty Seq.null
src/Control/Lens/Fold.hs view
@@ -1754,8 +1754,9 @@ -- 'foldr1Of' :: 'Traversal'' s a -> (a -> a -> a) -> s -> a -- @ foldr1Of :: HasCallStack => Getting (Endo (Maybe a)) s a -> (a -> a -> a) -> s -> a-foldr1Of l f xs = fromMaybe (error "foldr1Of: empty structure")- (foldrOf l mf Nothing xs) where+-- See: NOTE: [Inlining and arity]+foldr1Of l f = fromMaybe (error "foldr1Of: empty structure")+ . foldrOf l mf Nothing where mf x my = Just $ case my of Nothing -> x Just y -> f x y@@ -1780,7 +1781,8 @@ -- 'foldl1Of' :: 'Traversal'' s a -> (a -> a -> a) -> s -> a -- @ foldl1Of :: HasCallStack => Getting (Dual (Endo (Maybe a))) s a -> (a -> a -> a) -> s -> a-foldl1Of l f xs = fromMaybe (error "foldl1Of: empty structure") (foldlOf l mf Nothing xs) where+-- See: NOTE: [Inlining and arity]+foldl1Of l f = fromMaybe (error "foldl1Of: empty structure") . foldlOf l mf Nothing where mf mx y = Just $ case mx of Nothing -> y Just x -> f x y@@ -1800,7 +1802,8 @@ -- 'foldrOf'' :: 'Traversal'' s a -> (a -> r -> r) -> r -> s -> r -- @ foldrOf' :: Getting (Dual (Endo (Endo r))) s a -> (a -> r -> r) -> r -> s -> r-foldrOf' l f z0 xs = foldlOf l f' (Endo id) xs `appEndo` z0+-- See: NOTE: [Inlining and arity]+foldrOf' l f z0 = \xs -> foldlOf l f' (Endo id) xs `appEndo` z0 where f' (Endo k) x = Endo $ \ z -> k $! f x z {-# INLINE foldrOf' #-} @@ -1818,7 +1821,8 @@ -- 'foldlOf'' :: 'Traversal'' s a -> (r -> a -> r) -> r -> s -> r -- @ foldlOf' :: Getting (Endo (Endo r)) s a -> (r -> a -> r) -> r -> s -> r-foldlOf' l f z0 xs = foldrOf l f' (Endo id) xs `appEndo` z0+-- See: NOTE: [Inlining and arity]+foldlOf' l f z0 = \xs -> foldrOf l f' (Endo id) xs `appEndo` z0 where f' x (Endo k) = Endo $ \z -> k $! f z x {-# INLINE foldlOf' #-} @@ -1838,7 +1842,8 @@ -- 'foldr1Of'' :: 'Traversal'' s a -> (a -> a -> a) -> s -> a -- @ foldr1Of' :: HasCallStack => Getting (Dual (Endo (Endo (Maybe a)))) s a -> (a -> a -> a) -> s -> a-foldr1Of' l f xs = fromMaybe (error "foldr1Of': empty structure") (foldrOf' l mf Nothing xs) where+-- See: NOTE: [Inlining and arity]+foldr1Of' l f = fromMaybe (error "foldr1Of': empty structure") . foldrOf' l mf Nothing where mf x Nothing = Just $! x mf x (Just y) = Just $! f x y {-# INLINE foldr1Of' #-}@@ -1859,7 +1864,8 @@ -- 'foldl1Of'' :: 'Traversal'' s a -> (a -> a -> a) -> s -> a -- @ foldl1Of' :: HasCallStack => Getting (Endo (Endo (Maybe a))) s a -> (a -> a -> a) -> s -> a-foldl1Of' l f xs = fromMaybe (error "foldl1Of': empty structure") (foldlOf' l mf Nothing xs) where+-- See: NOTE: [Inlining and arity]+foldl1Of' l f = fromMaybe (error "foldl1Of': empty structure") . foldlOf' l mf Nothing where mf Nothing y = Just $! y mf (Just x) y = Just $! f x y {-# INLINE foldl1Of' #-}@@ -1881,7 +1887,8 @@ foldrMOf :: Monad m => Getting (Dual (Endo (r -> m r))) s a -> (a -> r -> m r) -> r -> s -> m r-foldrMOf l f z0 xs = foldlOf l f' return xs z0+-- See: NOTE: [Inlining and arity]+foldrMOf l f z0 = \xs -> foldlOf l f' return xs z0 where f' k x z = f x z >>= k {-# INLINE foldrMOf #-} @@ -1902,9 +1909,25 @@ foldlMOf :: Monad m => Getting (Endo (r -> m r)) s a -> (r -> a -> m r) -> r -> s -> m r-foldlMOf l f z0 xs = foldrOf l f' return xs z0+-- See: NOTE: [Inlining and arity]+foldlMOf l f z0 = \xs -> foldrOf l f' return xs z0 where f' x k z = f z x >>= k {-# INLINE foldlMOf #-}++-- NOTE: [Inlining and arity]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- GHC uses the following inlining heuristic: a function body is inlined if+-- all its arguments on the LHS are applied. So the following two definitions+-- are not equivalent from the inliner's PoV:+--+-- > foldlOf' l f z0 xs = ...+-- > foldlOf' l f z0 = \xs -> ...+--+-- GHC will be less eager to inline the first one and this results in+-- worse code. For example, a simple list summation using `sumOf` will be 8x slower+-- with the first version.+ -- | Check to see if this 'Fold' or 'Traversal' matches 1 or more entries. --
src/Control/Lens/Internal/Iso.hs view
@@ -33,6 +33,9 @@ import qualified Data.Vector.Storable as Storable import qualified Data.Vector.Unboxed as Unbox import Data.Vector.Unboxed (Unbox)+#if MIN_VERSION_vector(0,13,2)+import qualified Data.Vector.Strict as VectorStrict+#endif import qualified Data.Sequence as Seq import Data.Sequence (Seq) import Foreign.Storable (Storable)@@ -100,3 +103,8 @@ instance Storable a => Reversing (Storable.Vector a) where reversing = Storable.reverse++#if MIN_VERSION_vector(0,13,2)+instance Reversing (VectorStrict.Vector a) where+ reversing = VectorStrict.reverse+#endif
src/Control/Lens/Wrapped.hs view
@@ -150,6 +150,9 @@ import Data.Set (Set) import Data.Tagged import qualified Data.Vector as Vector+#if MIN_VERSION_vector(0,13,2)+import qualified Data.Vector.Strict as VectorStrict+#endif import qualified Data.Vector.Primitive as Prim import Data.Vector.Primitive (Prim) import qualified Data.Vector.Unboxed as Unboxed@@ -676,6 +679,14 @@ _Wrapped' = iso Storable.toList Storable.fromList {-# INLINE _Wrapped' #-} +#if MIN_VERSION_vector(0,13,2)+instance (t ~ Vector.Vector a') => Rewrapped (VectorStrict.Vector a) t+instance Wrapped (VectorStrict.Vector a) where+ type Unwrapped (VectorStrict.Vector a) = [a]+ _Wrapped' = iso VectorStrict.toList VectorStrict.fromList+ {-# INLINE _Wrapped' #-}+#endif+ -- * semigroupoids instance (t ~ WrappedApplicative f' a') => Rewrapped (WrappedApplicative f a) t@@ -873,7 +884,11 @@ #endif getErrorCall :: ErrorCall -> String+#if MIN_VERSION_base(4,21,0)+getErrorCall (ErrorCall x) = x+#else getErrorCall (ErrorCallWithLocation x _) = x+#endif {-# INLINE getErrorCall #-} getRecUpdError :: RecUpdError -> String