packages feed

data-diverse-lens (empty) → 0.1.0.0

raw patch · 10 files changed

+616/−0 lines, 10 filesdep +basedep +data-diversedep +data-diverse-lenssetup-changed

Dependencies added: base, data-diverse, data-diverse-lens, hspec, lens, tagged

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Louis Pan (c) 2017++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Louis Pan nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,6 @@+[![Hackage](https://img.shields.io/hackage/v/data-diverse-lens.svg)](https://hackage.haskell.org/package/data-diverse-lens)+[![Build Status](https://secure.travis-ci.org/louispan/data-diverse-lens.png?branch=master)](http://travis-ci.org/louispan/data-diverse-lens)++Provides "Iso"s & 'Len's for "Data.Diverse.Many" and 'Prism's for "Data.Diverse.Which".++Refer to [ManySpec.hs](https://github.com/louispan/data-diverse-lens/blob/master/test/Data/Diverse/Lens/ManySpec.hs) and [WhichSpec.hs](https://github.com/louispan/data-diverse/blob/master/test/Data/Diverse/Lens/WhichSpec.hs) for example usages.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ data-diverse-lens.cabal view
@@ -0,0 +1,47 @@+name:                data-diverse-lens+version:             0.1.0.0+synopsis:            Isos & Lens for Data.Diverse.Many and Prisms for Data.Diverse.Which+description:         Isos & Lens for Data.Diverse.Many and Prisms for Data.Diverse.Which+                     Refer to [ManySpec.hs](https://github.com/louispan/data-diverse-lens/blob/master/test/Data/Diverse/Lens/ManySpec.hs) and [WhichSpec.hs](https://github.com/louispan/data-diverse-lens/blob/master/test/Data/Diverse/Lens/WhichSpec.hs) for example usages.+homepage:            https://github.com/louispan/data-diverse-lens#readme+license:             BSD3+license-file:        LICENSE+author:              Louis Pan+maintainer:          louis@pan.me+copyright:           2017 Louis Pan+category:            Data, Records+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10+tested-with:         GHC == 8.0.2++library+  hs-source-dirs:      src+  exposed-modules:     Data.Diverse.Lens+                       Data.Diverse.Lens.Many+                       Data.Diverse.Lens.Which+  build-depends:       base >= 4.7 && < 5+                     , data-diverse >= 0.6 && < 1+                     , lens >= 4 && < 5+                     , tagged >= 0.8.5 && < 1+  ghc-options:         -Wall+  default-language:    Haskell2010++test-suite data-diverse-lens-test+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Spec.hs+  other-modules:       Data.Diverse.Lens.ManySpec+                       Data.Diverse.Lens.WhichSpec+  build-depends:       base+                     , data-diverse >= 0.6 && < 1+                     , data-diverse-lens+                     , hspec >= 2 && < 3+                     , lens >= 4 && < 5+                     , tagged >= 0.8.5 && < 1+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N -Wall+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/louispan/data-diverse-lens
+ src/Data/Diverse/Lens.hs view
@@ -0,0 +1,11 @@+module Data.Diverse.Lens (+    -- * Re-export "Data.Diverse" for convenience+      module Data.Diverse+    -- * Iso's, Lens and Prisms for 'Data.Diverse.Many.Many' and 'Data.Diverse.Which.Which'+    , module Data.Diverse.Lens.Many+    , module Data.Diverse.Lens.Which+    ) where++import Data.Diverse+import Data.Diverse.Lens.Many+import Data.Diverse.Lens.Which
+ src/Data/Diverse/Lens/Many.hs view
@@ -0,0 +1,198 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++module Data.Diverse.Lens.Many (+      -- * Isomorphism+      _Many+    , _Many'++    -- * Single field+    -- ** Lens for a single field+    , item+    , item'+    , itemL+    , itemL'+    , itemN+    , itemN'++    -- * Multiple fields+    -- ** Lens for multiple fields+    , project+    , project'+    , projectL+    , projectL'+    , projectN+    , projectN'++    ) where++import Control.Lens+import Data.Proxy+import Data.Tagged+import Data.Diverse.Many+import Data.Diverse.TypeLevel++-- | @_Many = iso fromMany toMany@+_Many :: IsMany t xs a => Iso' (Many xs) (t xs a)+_Many = iso fromMany toMany+{-# INLINE _Many #-}++-- | @_Many' = iso fromMany' toMany'@+_Many' :: IsMany Tagged xs a => Iso' (Many xs) a+_Many' = iso fromMany' toMany'+{-# INLINE _Many' #-}++-----------------------------------------------------------------------++-- | 'fetch' ('view' 'item') and 'replace' ('set' 'item') in 'Lens'' form.+--+-- @+-- let x = (5 :: Int) './' False './' \'X' './' Just \'O' './' 'nil'+-- x '^.' 'item' \@Int \`shouldBe` 5+-- (x '&' 'item' \@Int .~ 6) \`shouldBe` (6 :: Int) './' False './' \'X' './' Just \'O' './' 'nil'+-- @+item :: forall x xs. UniqueMember x xs => Lens' (Many xs) x+item = lens fetch replace+{-# INLINE item #-}++-- | Polymorphic version of 'item'+item' :: forall x y xs. UniqueMember x xs => Lens (Many xs) (Many (Replace x y xs)) x y+item' = lens fetch (replace' @x @y Proxy)+{-# INLINE item' #-}+++-- | 'fetchL' ('view' 'itemL') and 'replaceL' ('set' 'itemL') in 'Lens'' form.+--+-- @+-- let x = (5 :: Int) './' Tagged \@Foo False './' Tagged \@Bar \'X' './' 'nil'+-- x '^.' 'itemL' \@Foo Proxy \`shouldBe` Tagged \@Foo False+-- (x '&' 'itemL' \@Foo Proxy '.~' Tagged \@Foo True) \`shouldBe` (5 :: Int) './' Tagged \@Foo True './' Tagged \@Bar \'X' './' 'nil'+-- @+itemL :: forall l xs x proxy. (UniqueLabelMember l xs, x ~ KindAtLabel l xs) => proxy l -> Lens' (Many xs) x+itemL p = lens (fetchL p) (replaceL p)+{-# INLINE itemL #-}++-- | Polymorphic version of 'itemL'+--+-- @+-- let x = (5 :: Int) './' Tagged @Foo False './' Tagged \@Bar \'X' './' 'nil'+-- (x '&' itemL' \@Foo Proxy '.~' \"foo") \`shouldBe` (5 :: Int) './' \"foo" './' Tagged \@Bar \'X' './' 'nil'+-- @+itemL' :: forall l y xs x proxy. (UniqueLabelMember l xs, x ~ KindAtLabel l xs) => proxy l -> Lens (Many xs) (Many (Replace x y xs)) x y+itemL' p = lens (fetchL p) (replaceL' p)+{-# INLINE itemL' #-}+++-- | 'fetchN' ('view' 'item') and 'replaceN' ('set' 'item') in 'Lens'' form.+--+-- @+-- let x = (5 :: Int) './' False './' \'X' './' Just \'O' './' (6 :: Int) './' Just \'A' ./ nil+-- x '^.' 'itemN' (Proxy \@0) \`shouldBe` 5+-- (x '&' 'itemN' (Proxy @0) '.~' 6) \`shouldBe` (6 :: Int) './' False './' \'X' './' Just \'O' './' (6 :: Int) './' Just \'A' './' 'nil'+-- @+itemN ::  forall n x xs proxy. MemberAt n x xs => proxy n -> Lens' (Many xs) x+itemN p = lens (fetchN p) (replaceN p)+{-# INLINE itemN #-}+++-- | Polymorphic version of 'itemN'+itemN' ::  forall n x y xs proxy. MemberAt n x xs => proxy n -> Lens (Many xs) (Many (ReplaceIndex n y xs)) x y+itemN' p = lens (fetchN p) (replaceN' @n @x @y p)+{-# INLINE itemN' #-}++-----------------------------------------------------------------------++-- | 'select' ('view' 'project') and 'amend' ('set' 'project') in 'Lens'' form.+--+-- @+-- 'project' = 'lens' 'select' 'amend'+-- @+--+-- @+-- let x = (5 :: Int) './' False './' \'X' './' Just \'O' './' 'nil'+-- x '^.' ('project' \@'[Int, Maybe Char]) \`shouldBe` (5 :: Int) './' Just \'O' './' 'nil'+-- (x '&' ('project' \@'[Int, Maybe Char]) '.~' ((6 :: Int) './' Just 'P' './' 'nil')) \`shouldBe`+--     (6 :: Int) './' False './' \'X' './' Just \'P' './' 'nil'+-- @+project+    :: forall smaller larger.+       (Select smaller larger, Amend smaller larger)+    => Lens' (Many larger) (Many smaller)+project = lens select amend+{-# INLINE project #-}++-- | Polymorphic version of project'+project'+    :: forall smaller smaller' larger zipped.+       (Select smaller larger, Amend' smaller smaller' larger zipped)+    => Lens (Many larger) (Many (Replaces smaller smaller' larger)) (Many smaller) (Many smaller')+project' = lens select (amend' @smaller @smaller' Proxy)+{-# INLINE project' #-}++-- | 'selectL' ('view' 'projectL') and 'amendL' ('set' 'projectL') in 'Lens'' form.+--+-- @+-- let x = False './' Tagged \@\"Hi" (5 :: Int) './' Tagged \@Foo False './' Tagged \@Bar \'X' './' Tagged \@\"Bye" \'O' './' 'nil'+-- x '^.' ('projectL' \@'[Foo, Bar] Proxy) \`shouldBe` Tagged \@Foo False './' Tagged \@Bar \'X' './' nil+-- (x '&' ('projectL' \@'[\"Hi", \"Bye"] Proxy) '.~' (Tagged \@\"Hi" (6 :: Int) './' Tagged \@\"Bye" \'P' './' nil)) '`shouldBe`+--     False './' Tagged \@\"Hi" (6 :: Int) './' Tagged \@Foo False './' Tagged \@Bar \'X' './' Tagged \@\"Bye" \'P' './' 'nil'+-- @+projectL+    :: forall ls smaller larger proxy.+       ( Select smaller larger+       , Amend smaller larger+       , smaller ~ KindsAtLabels ls larger+       , IsDistinct ls+       , UniqueLabels ls larger)+    => proxy ls -> Lens' (Many larger) (Many smaller)+projectL p = lens (selectL p) (amendL p)+{-# INLINE projectL #-}++-- | Polymorphic version of projectL'+--+-- @+-- let x = False './' Tagged \@\"Hi" (5 :: Int) './' Tagged \@Foo False './' Tagged \@Bar \'X' './' Tagged \@\"Bye" \'O' './' 'nil'+-- (x '&' ('projectL'' \@'[\"Hi", \"Bye"] Proxy) '.~' (True './' Tagged \@\"Changed" False './' 'nil')) \`shouldBe`+--     False './' True './' Tagged \@Foo False './' Tagged \@Bar \'X' './' Tagged \@\"Changed" False './' 'nil'+-- @+projectL'+    :: forall ls smaller smaller' larger proxy zipped.+       ( Select smaller larger+       , Amend' smaller smaller' larger zipped+       , smaller ~ KindsAtLabels ls larger+       , IsDistinct ls+       , UniqueLabels ls larger)+    => proxy ls -> Lens (Many larger) (Many (Replaces smaller smaller' larger)) (Many smaller) (Many smaller')+projectL' p = lens (selectL p) (amendL' p)+{-# INLINE projectL' #-}++-- | 'selectN' ('view' 'projectN') and 'amendN' ('set' 'projectN') in 'Lens'' form.+--+-- @+-- 'projectN' = 'lens' 'selectN' 'amendN'+-- @+--+-- @+-- let x = (5 :: Int) './' False './' \'X' './' Just \'O' './' (6 :: Int) './' Just \'A' './' 'nil'+-- x '^.' ('projectN' \@'[5, 4, 0] Proxy) \`shouldBe` Just \'A' './' (6 :: Int) './' (5 ::Int) './' 'nil'+-- (x '&' ('projectN' \@'[5, 4, 0] Proxy) '.~' (Just \'B' './' (8 :: Int) './' (4 ::Int) './' nil)) \`shouldBe`+--     (4 :: Int) './' False './' \'X' './' Just \'O' './' (8 :: Int) './' Just \'B' './' 'nil'+-- @+projectN+    :: forall ns smaller larger proxy.+       (SelectN ns smaller larger, AmendN ns smaller larger)+    => proxy ns -> Lens' (Many larger) (Many smaller)+projectN p = lens (selectN p) (amendN p)+{-# INLINE projectN #-}++-- | Polymorphic version of 'projectN'+projectN'+    :: forall ns smaller smaller' larger proxy zipped.+       (SelectN ns smaller larger, AmendN' ns smaller smaller' larger zipped)+    => proxy ns -> Lens (Many larger) (Many (ReplacesIndex ns smaller' larger)) (Many smaller) (Many smaller')+projectN' p = lens (selectN p) (amendN' p)+{-# INLINE projectN' #-}
+ src/Data/Diverse/Lens/Which.hs view
@@ -0,0 +1,133 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE RankNTypes #-}++module Data.Diverse.Lens.Which (+      -- * Single type+      -- ** Prism+      facet+    , facetL+    , facetN++      -- * Multiple types+      -- ** Prism+    , inject+    , injectL+    , injectN++    ) where++import Control.Lens+import Data.Diverse.Which+import Data.Diverse.TypeLevel++-----------------------------------------------------------------++-- | Utility to convert Either to Maybe+hush :: Either a b -> Maybe b+hush = either (const Nothing) Just++-----------------------------------------------------------------++-- | 'pick' ('review' 'facet') and 'trial' ('preview' 'facet') in 'Prism'' form.+--+-- @+-- 'facet' = 'prism'' 'pick' (either (const Nothing) Just . 'trial')+-- @+--+-- @+-- let y = 'review' ('facet' \@Int) (5 :: Int) :: 'Which' '[Bool, Int, Char, Bool, Char] -- 'pick'+--     x = 'preview' ('facet' \@Int) y -- 'trial'+-- x \`shouldBe` (Just 5)+-- @+facet :: forall x xs. (UniqueMember x xs) => Prism' (Which xs) x+facet = prism' pick (hush . trial)+{-# INLINE facet #-}++-- | 'pickL' ('review' 'facetL') and 'trialL' ('preview' 'facetL') in 'Prism'' form.+--+-- @+-- let y = 'review' ('facetL' \@Bar Proxy) (Tagged (5 :: Int)) :: Which '[Tagged Foo Bool, Tagged Bar Int, Char, Bool, Char]+--     x = 'preview' ('facetL' \@Bar Proxy) y+-- x \`shouldBe` (Just (Tagged 5))+-- @+facetL :: forall l xs x proxy. (UniqueLabelMember l xs, x ~ KindAtLabel l xs) => proxy l -> Prism' (Which xs) x+facetL p = prism' (pickL p) (hush . trialL p)+{-# INLINE facetL #-}++-- | 'pickN' ('review' 'facetN') and 'trialN' ('preview' 'facetN') in 'Prism'' form.+--+-- @+-- 'facetN' p = 'prism'' ('pickN' p) (either (const Nothing) Just . 'trialN' p)+-- @+--+-- @+-- let y = 'review' ('facetN' (Proxy \@4)) (5 :: Int) :: 'Which' '[Bool, Int, Char, Bool, Int, Char] -- 'pickN'+--     x = 'preview' ('facetN' (Proxy \@4)) y -- 'trialN'+-- x \`shouldBe` (Just 5)+-- @+facetN :: forall n xs x proxy. (MemberAt n x xs) => proxy n -> Prism' (Which xs) x+facetN p = prism' (pickN p) (hush . trialN p)+{-# INLINE facetN #-}++------------------------------------------------------------------+++-- | 'diversify' ('review' 'inject') and 'reinterpret' ('preview' 'inject') in 'Prism'' form.+--+-- @+-- let x = 'pick' (5 :: Int) :: 'Which' '[String, Int]+--     y = 'review' ('inject' \@_ \@[Bool, Int, Char, String]) x -- 'diversify'+-- y \`shouldBe` pick (5 :: Int) :: 'Which' '[Bool, Int, Char, String]+-- let y' = 'preview' ('inject' \@[String, Int]) y -- 'reinterpret'+-- y' \`shouldBe` Just (pick (5 :: Int)) :: Maybe ('Which' '[String, Int])+-- @+inject+    :: forall branch tree.+       ( Diversify tree branch+       , Reinterpret branch tree+       )+    => Prism' (Which tree) (Which branch)+inject = prism' diversify (hush . reinterpret)+{-# INLINE inject #-}+++-- | 'diversifyL' ('review' 'injectL') and 'reinterpretL' ('preview' 'injectL') in 'Prism'' form.+--+-- @+-- let t = 'pick' \@[Tagged Bar Int, Tagged Foo Bool, Tagged Hi Char, Tagged Bye Bool] (5 :: Tagged Bar Int)+--     b = 'pick' \@'[Tagged Foo Bool, Tagged Bar Int] (5 :: Tagged Bar Int)+--     t' = 'review' ('injectL' \@[Foo, Bar] \@_ \@[Tagged Bar Int, Tagged Foo Bool, Tagged Hi Char, Tagged Bye Bool] Proxy) b+--     b' = 'preview' ('injectL' \@[Foo, Bar] Proxy) t'+-- t \`shouldBe` t'+-- b' \`shouldBe` Just b+-- @+injectL+    :: forall ls branch tree proxy.+       ( Diversify tree branch+       , Reinterpret branch tree+       , branch ~ KindsAtLabels ls tree+       , UniqueLabels ls tree+       , IsDistinct ls+       )+    => proxy ls -> Prism' (Which tree) (Which branch)+injectL p = prism' (diversifyL p) (hush . reinterpretL p)+{-# INLINE injectL #-}++-- | 'diversifyN' ('review' 'injectN') and 'reinterpretN' ('preview' 'injectN') in 'Prism'' form.+--+-- @+-- let x = 'pick' (5 :: Int) :: 'Which' '[String, Int]+--     y = 'review' (injectN \@[3, 1] \@_ \@[Bool, Int, Char, String] Proxy) x -- 'diversifyN'+-- y \`shouldBe` pick (5 :: Int) :: 'Which' '[Bool, Int, Char, String]+-- let y' = 'preview' ('injectN' @[3, 1] \@[String, Int] Proxy) y -- 'reinterpertN''+-- y' \`shouldBe` Just ('pick' (5 :: Int)) :: Maybe ('Which' '[String, Int])+-- @+injectN+    :: forall indices branch tree proxy.+       ( DiversifyN indices tree branch+       , ReinterpretN indices branch tree+       )+    => proxy indices -> Prism' (Which tree) (Which branch)+injectN p = prism' (diversifyN p) (reinterpretN p)+{-# INLINE injectN #-}
+ test/Data/Diverse/Lens/ManySpec.hs view
@@ -0,0 +1,117 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++module Data.Diverse.Lens.ManySpec (main, spec) where++import Control.Lens+import Data.Diverse+import Data.Diverse.Lens+import Data.Tagged+import Data.Typeable+import Test.Hspec++-- `main` is here so that this module can be run from GHCi on its own.  It is+-- not needed for automatic spec discovery.+main :: IO ()+main = hspec spec++data Foo+data Bar++spec :: Spec+spec = do+    describe "Many" $ do++        it "can converted to and from a tuple using 'Many'' Iso" $ do+            let x = (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ nil+                t = ((5 :: Int), False, 'X', Just 'O')+            x `shouldBe` review _Many' t+            t `shouldBe` view _Many' x++        it "has getter/setter lens using 'item'" $ do+            let x = (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ nil+            x ^. item @Int `shouldBe` 5+            (x & item @Int .~ 6) `shouldBe` (6 :: Int) ./ False ./ 'X' ./ Just 'O' ./ nil+            x ^. item @Bool `shouldBe` False+            (x & item @Bool .~ True) `shouldBe` (5 :: Int) ./ True ./ 'X' ./ Just 'O' ./ nil+            x ^. item @Char `shouldBe` 'X'+            x ^. item @(Maybe Char) `shouldBe` Just 'O'++        it "has polymorphic getter/setter lens using 'item''" $ do+            let x = (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ nil+            (x & item' @(Maybe Char) .~ Just 'P') `shouldBe` (5 :: Int) ./ False ./ 'X' ./ Just 'P' ./ nil+            (x & item' @Int .~ 'Z') `shouldBe` 'Z' ./ False ./ 'X' ./ Just 'O' ./ nil+            (x & item' @Bool .~ 'Z') `shouldBe` (5 :: Int) ./ 'Z' ./ 'X' ./ Just 'O' ./ nil+            (x & item' @Char .~ True) `shouldBe` (5 :: Int) ./ False ./ True ./ Just 'O' ./ nil+            (x & item' @(Maybe Char) .~ 'P') `shouldBe` (5 :: Int) ./ False ./ 'X' ./ 'P' ./ nil++        it "has getter/setter lens using 'item'" $ do+            let x = (5 :: Int) ./ Tagged @Foo False ./ Tagged @Bar 'X' ./ nil+            x ^. itemL @Foo Proxy `shouldBe` Tagged @Foo False+            (x & itemL @Foo Proxy .~ Tagged @Foo True) `shouldBe` (5 :: Int) ./ Tagged @Foo True ./ Tagged @Bar 'X' ./ nil++        it "has polymorphic getter/setter lens using 'itemL''" $ do+            let x = (5 :: Int) ./ Tagged @Foo False ./ Tagged @Bar 'X' ./ nil+            (x & itemL' @Foo Proxy .~ "foo") `shouldBe` (5 :: Int) ./ "foo" ./ Tagged @Bar 'X' ./ nil++        it "has getter/setter lens for duplicate fields using 'itemN'" $ do+            let x = (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ (6 :: Int) ./ Just 'A' ./ nil+            x ^. itemN (Proxy @0) `shouldBe` 5+            (x & itemN (Proxy @0) .~ 6) `shouldBe` (6 :: Int) ./ False ./ 'X' ./ Just 'O' ./ (6 :: Int) ./ Just 'A' ./ nil+            x ^. itemN (Proxy @1) `shouldBe` False+            (x & itemN (Proxy @1) .~ True) `shouldBe` (5 :: Int) ./ True ./ 'X' ./ Just 'O' ./ (6 :: Int) ./ Just 'A' ./ nil+            x ^. itemN (Proxy @2) `shouldBe` 'X'+            (x & itemN (Proxy @2) .~ 'O') `shouldBe` (5 :: Int) ./ False ./ 'O' ./ Just 'O' ./ (6 :: Int) ./ Just 'A' ./ nil+            x ^. itemN (Proxy @3) `shouldBe` Just 'O'+            (x & itemN (Proxy @3) .~ Just 'P') `shouldBe` (5 :: Int) ./ False ./ 'X' ./ Just 'P' ./ (6 :: Int) ./ Just 'A' ./ nil+            x ^. itemN (Proxy @4) `shouldBe` 6+            (x & itemN (Proxy @4) .~ 7) `shouldBe` (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ (7 :: Int) ./ Just 'A' ./ nil+            x ^. itemN (Proxy @5) `shouldBe` Just 'A'+            (x & itemN (Proxy @5) .~ Just 'B') `shouldBe` (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ (6 :: Int) ./ Just 'B' ./ nil++        it "has polymorphic getter/setter lens for duplicate fields using 'itemN''" $ do+            let x = (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ (6 :: Int) ./ Just 'A' ./ nil+            (x & itemN' (Proxy @0) .~ "Foo") `shouldBe` "Foo" ./ False ./ 'X' ./ Just 'O' ./ (6 :: Int) ./ Just 'A' ./ nil+            (x & itemN' (Proxy @1) .~ "Foo") `shouldBe` (5 :: Int) ./ "Foo" ./ 'X' ./ Just 'O' ./ (6 :: Int) ./ Just 'A' ./ nil+            (x & itemN' (Proxy @2) .~ "Foo") `shouldBe` (5 :: Int) ./ False ./ "Foo" ./ Just 'O' ./ (6 :: Int) ./ Just 'A' ./ nil+            (x & itemN' (Proxy @3) .~ "Foo") `shouldBe` (5 :: Int) ./ False ./ 'X' ./ "Foo" ./ (6 :: Int) ./ Just 'A' ./ nil+            (x & itemN' (Proxy @4) .~ "Foo") `shouldBe` (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ "Foo" ./ Just 'A' ./ nil+            (x & itemN' (Proxy @5) .~ "Foo") `shouldBe` (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ (6 :: Int) ./ "Foo" ./ nil++        it "has getter/setter lens for multiple fields using 'project'" $ do+            let x = (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ nil+            x ^. (project @'[Int, Maybe Char]) `shouldBe` (5 :: Int) ./ Just 'O' ./ nil+            (x & (project @'[Int, Maybe Char]) .~ ((6 :: Int) ./ Just 'P' ./ nil)) `shouldBe`+                (6 :: Int) ./ False ./ 'X' ./ Just 'P' ./ nil++        it "has polymorphic getter/setter lens for multiple fields using 'project'" $ do+            let x = (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ nil+            (x & (project' @'[Int, Maybe Char]) .~ ("Foo" ./ Just "Bar" ./ nil)) `shouldBe`+                "Foo" ./ False ./ 'X' ./ Just "Bar" ./ nil++        it "has getter/setter lens for multiple labelled fields using 'projectL'" $ do+            let x = False ./ Tagged @"Hi" (5 :: Int) ./ Tagged @Foo False ./ Tagged @Bar 'X' ./ Tagged @"Bye" 'O' ./ nil+            x ^. (projectL @'[Foo, Bar] Proxy) `shouldBe` Tagged @Foo False ./ Tagged @Bar 'X' ./ nil+            (x & (projectL @'["Hi", "Bye"] Proxy) .~ (Tagged @"Hi" (6 :: Int) ./ Tagged @"Bye" 'P' ./ nil)) `shouldBe`+                False ./ Tagged @"Hi" (6 :: Int) ./ Tagged @Foo False ./ Tagged @Bar 'X' ./ Tagged @"Bye" 'P' ./ nil++        it "has polymorphic getter/setter lens for multiple labelled fields using 'projectL''" $ do+            let x = False ./ Tagged @"Hi" (5 :: Int) ./ Tagged @Foo False ./ Tagged @Bar 'X' ./ Tagged @"Bye" 'O' ./ nil+            (x & (projectL' @'["Hi", "Bye"] Proxy) .~ (True ./ Tagged @"Changed" False ./ nil)) `shouldBe`+                False ./ True ./ Tagged @Foo False ./ Tagged @Bar 'X' ./ Tagged @"Changed" False ./ nil++        it "has getter/setter lens for multiple fields with duplicates using 'projectN'" $ do+            let x = (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ (6 :: Int) ./ Just 'A' ./ nil+            x ^. (projectN @'[5, 4, 0] Proxy) `shouldBe` Just 'A' ./ (6 :: Int) ./ (5 ::Int) ./ nil+            (x & (projectN @'[5, 4, 0] Proxy) .~ (Just 'B' ./ (8 :: Int) ./ (4 ::Int) ./ nil)) `shouldBe`+                (4 :: Int) ./ False ./ 'X' ./ Just 'O' ./ (8 :: Int) ./ Just 'B' ./ nil++        it "has polymorphic getter/setter lens for multiple fields with duplicates using 'projectN'" $ do+            let x = (5 :: Int) ./ False ./ 'X' ./ Just 'O' ./ (6 :: Int) ./ Just 'A' ./ nil+            (x & (projectN' @'[5, 4, 0] Proxy) .~ (Just "Foo" ./ (8 :: Int) ./ "Bar" ./ nil)) `shouldBe`+                "Bar" ./ False ./ 'X' ./ Just 'O' ./ (8 :: Int) ./ Just "Foo" ./ nil
+ test/Data/Diverse/Lens/WhichSpec.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}++module Data.Diverse.Lens.WhichSpec (main, spec) where++import Control.Lens+import Data.Diverse+import Data.Diverse.Lens+import Data.Proxy+import Data.Tagged+import Test.Hspec++data Foo+data Bar+data Hi+data Bye++-- `main` is here so that this module can be run from GHCi on its own.  It is+-- not needed for automatic spec discovery.+main :: IO ()+main = hspec spec++-- -- | Utility to convert Either to Maybe+-- hush :: Either a b -> Maybe b+-- hush = either (const Nothing) Just++spec :: Spec+spec = do+    describe "Which" $ do++        it "can be constructed and destructed by type with 'facet'" $ do+            let y = review (facet @Int) (5 :: Int) :: Which '[Bool, Int, Char, Bool, Char]+                x = preview (facet @Int) y+            x `shouldBe` (Just 5)++        it "can be constructed and destructed by label with 'facetL'" $ do+            let y = review (facetL @Bar Proxy) (Tagged (5 :: Int)) :: Which '[Tagged Foo Bool, Tagged Bar Int, Char, Bool, Char]+                x = preview (facetL @Bar Proxy) y+            x `shouldBe` (Just (Tagged 5))++        it "can be constructed and destructed by index with 'facetN'" $ do+            let y = review (facetN (Proxy @4)) (5 :: Int) :: Which '[Bool, Int, Char, Bool, Int, Char]+                x = preview (facetN (Proxy @4)) y+            x `shouldBe` (Just 5)++        it "can be 'diversify'ed and 'reinterpreted' by type with 'inject'" $ do+            let x = pick (5 :: Int) :: Which '[String, Int]+                y = review (inject @_ @[Bool, Int, Char, String]) x+            y `shouldBe` pick (5 :: Int)+            let y' = preview (inject @[String, Int]) y+            y' `shouldBe` Just (pick (5 :: Int))++        it "can be 'diversifyL'ed and 'reinterpretedL' by label with 'injectL'" $ do+            let t = pick @[Tagged Bar Int, Tagged Foo Bool, Tagged Hi Char, Tagged Bye Bool] (5 :: Tagged Bar Int)+                b = pick @'[Tagged Foo Bool, Tagged Bar Int] (5 :: Tagged Bar Int)+                t' = review (injectL @[Foo, Bar] @_ @[Tagged Bar Int, Tagged Foo Bool, Tagged Hi Char, Tagged Bye Bool] Proxy) b+                b' = preview (injectL @[Foo, Bar] Proxy) t'+            t `shouldBe` t'+            b' `shouldBe` Just b++        it "can be 'diversifyN'ed and 'reinterpretedN' by index with 'injectN'" $ do+            let x = pick (5 :: Int) :: Which '[String, Int]+                y = review (injectN @[3, 1] @_ @[Bool, Int, Char, String] Proxy) x+            y `shouldBe` pick (5 :: Int)+            let y' = preview (injectN @[3, 1] @[String, Int] Proxy) y+            y' `shouldBe` Just (pick (5 :: Int))
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}