{-# LANGUAGE TemplateHaskell #-} ----------------------------------------------------------------------------- -- | -- Module : Generics.Pointless.DLenses.Examples.Examples -- Copyright : (c) 2011 University of Minho -- License : BSD3 -- -- Maintainer : hpacheco@di.uminho.pt -- Stability : experimental -- Portability : non-portable -- -- Pointless Lenses: -- bidirectional lenses with point-free programming -- -- This module provides examples of delta-lenses. -- ----------------------------------------------------------------------------- module Generics.Pointless.DLenses.Examples.Examples where import Data.Shape import Generics.Pointless.DLenses.Combinators import Generics.Pointless.DLenses.ShapeCombinators import Generics.Pointless.DLenses import Generics.Pointless.DLenses.RecursionPatterns import Generics.Pointless.HFunctors import Generics.Pointless.Lenses (Lens) import qualified Generics.Pointless.Lenses as Lns import Generics.Pointless.Lenses.Combinators import Generics.Pointless.Lenses.Examples.Examples import Generics.Pointless.Combinators import Generics.Pointless.Functors import qualified Data.Set as Set import Test.QuickCheck hiding ((><)) import Data.DeriveTH -- * Mapping srcMap = [(1,'a'),(2,'b'),(3,'c')] lnsMap :: DLens [] (Int,Char) [] Int lnsMap = map_dlns (fst_lns (const 'x')) getMap = get lnsMap srcMap tgtMap = [0,3,1] putMap = put lnsMap (tgtMap,srcMap) dV where dV = Set.fromList [(1,2),(2,0)] checkMap = testDLens lnsMap -- * Semantic halve_dlns :: a -> DLens [] a [] a halve_dlns d = sem_dlns d rear_bias skel halve where halve :: [a] -> [a] halve [] = [] halve (x:xs) = x : halve' (xs,xs) halve' :: ([a],[a]) -> [a] halve' (xs,[]) = [] halve' (xs,[y]) = [] halve' (x:xs,y:z:zs) = x : halve' (xs,zs) skel = halve_lns _L srcHalve = [1,2,3,4] lnsHalve :: DLens [] Int [] Int lnsHalve = halve_dlns (-1) getHalve = get lnsHalve srcHalve tgtHalve = [0,2,1] createHalve = create lnsHalve tgtHalve putHalve = put lnsHalve (tgtHalve,srcHalve) dV where dV = Set.fromList [(1,0),(2,1)] invHalve = quickCheck (\s -> shape (Lns.get (halve_lns (_L::Int)) s) == shape (get (halve_dlns _L) s)) checkHalve = testDLens lnsHalve -- * Filtering (user-defined) data LE a = NilE | ConsE (Either a a) (LE a) deriving (Eq,Show) $( derive makeArbitrary ''LE ) instance FMonoid LE where fzero = NilE fplus NilE l = l fplus l NilE = l fplus (ConsE x xs) r = ConsE x (fplus xs r) type instance HF LE = HConst One :+~: (HParam :+~: HParam) :*~: HId instance Hu LE where hout NilE = InlF $ ConsF _L hout (ConsE (Left x) xs) = InrF $ ProdF (InlF $ IdF x) xs hout (ConsE (Right x) xs) = InrF $ ProdF (InrF $ IdF x) xs hinn (InlF (ConsF _)) = NilE hinn (InrF (ProdF (InlF (IdF x)) xs)) = ConsE (Left x) xs hinn (InrF (ProdF (InrF (IdF x)) xs)) = ConsE (Right x) xs instance Shapely LE where traverse f = (hinn >< id) . traverse f . (hout >< id) filter_dlns :: DLens LE a [] a filter_dlns = cata_dlns _L (((\/<~) p hinn_dlns (snd_dlns _L)) .<~ coassocl_dlns .<~ (id_dlns -|-<~ distl_dlns)) where p _ = Left _L srcFilter = ConsE (Left 1) $ ConsE (Right 5) $ ConsE (Left 2) $ ConsE (Right 6) NilE tgtFilter = [0,1] lnsFilter :: DLens LE Int [] Int lnsFilter = filter_dlns getFilter = get lnsFilter srcFilter putFilter = put lnsFilter (tgtFilter,srcFilter) dV where dV = Set.fromList [(1,0)] checkFilter = testDLens lnsFilter -- * Filtering (composition fixed point) instance (Arbitrary (f (g a))) => Arbitrary ((f :@: g) a) where arbitrary = do {x <- arbitrary; return (CompF x)} instance (Arbitrary (f a),Arbitrary (g a)) => Arbitrary ((f :+: g) a) where arbitrary = oneof [do {x <- arbitrary; return (InlF x)},do {x <- arbitrary; return (InrF x)}] instance (Arbitrary (f a),Arbitrary (g a)) => Arbitrary ((f :*: g) a) where arbitrary = do {x <- arbitrary; y <- arbitrary; return (ProdF x y)} instance Arbitrary a => Arbitrary (Id a) where arbitrary = do {x <- arbitrary; return (IdF x)} instance Arbitrary c => Arbitrary ((Const c) a) where arbitrary = do {x <- arbitrary; return (ConsF x)} instance Hu ([] :@: (Id :+: Id)) where hout (CompF []) = InlF $ ConsF _L hout (CompF (x:xs)) = InrF $ ProdF x (CompF xs) hinn (InlF (ConsF _)) = CompF [] hinn (InrF (ProdF x (CompF xs))) = CompF (x:xs) filter'_dlns :: DLens ([] :@: (Id :+: Id)) a [] a filter'_dlns = cata_dlns _L (((\/<~) p hinn_dlns (snd_dlns _L)) .<~ coassocl_dlns .<~ (id_dlns -|-<~ distl_dlns)) where p _ = Left _L srcFilter' = CompF [InlF (IdF 1),InrF (IdF 5),InlF (IdF 2),InrF (IdF 6)] tgtFilter' = [0,1] lnsFilter' :: DLens ([] :@: (Id :+: Id)) Int [] Int lnsFilter' = filter'_dlns getFilter' = get lnsFilter' srcFilter' putFilter' = put lnsFilter' (tgtFilter',srcFilter') dV where dV = Set.fromList [(1,0)] checkFilter' = testDLens lnsFilter' -- * Tree left spine (fold) data Tree a = Empty | Node a (Tree a) (Tree a) deriving (Eq,Show) $( derive makeArbitrary ''Tree ) instance Shapely Tree where traverse f = (hinn >< id) . traverse f . (hout >< id) type instance HF Tree = HConst One :+~: HParam :*~: (HId :*~: HId) instance Hu Tree where hout Empty = InlF $ ConsF _L hout (Node x l r) = InrF $ ProdF (IdF x) (ProdF l r) hinn (InlF (ConsF _)) = Empty hinn (InrF (ProdF (IdF x) (ProdF l r))) = Node x l r instance FMonoid Tree where fzero = Empty fplus t Empty = t fplus t (Node x l r) = Node x (fplus t l) r lspine_dlns :: DLens Tree a [] a lspine_dlns = cata_dlns _L f where f = hinn_dlns .<~ (id_dlns -|-<~ id_dlns ><<~ fst_dlns g) g = const [] lnsSpine :: DLens Tree Int [] Int lnsSpine = lspine_dlns srcSpine = Node 1 (Node 2 Empty Empty) (Node 3 Empty Empty) tgtSpine = [0,1,2] getSpine = get lnsSpine srcSpine putSpine = put lnsSpine (tgtSpine,srcSpine) dV where dV = Set.fromList [(1,0),(2,1)] checkSpine = testDLens lnsSpine -- * Tree left spine (unfold) lspine'_dlns :: DLens Tree a [] a lspine'_dlns = ana_dlns _L f where f = (id_dlns -|-<~ id_dlns ><<~ fst_dlns g) .<~ hout_dlns g = const Empty lnsSpine' :: DLens Tree Int [] Int lnsSpine' = lspine'_dlns srcSpine' = Node 1 (Node 2 Empty Empty) (Node 3 Empty Empty) tgtSpine' = [0,1,2] getSpine' = get lnsSpine' srcSpine' putSpine' = put lnsSpine' (tgtSpine',srcSpine') dV where dV = Set.fromList [(1,0),(2,1)] checkSpine' = testDLens lnsSpine' -- * Sieve sieve_dlns :: a -> DLens [] a [] a sieve_dlns a = ana_dlns _L f where f = (((\/<~) p id_dlns id_dlns) -|-<~ id_dlns) .<~ coassocl_dlns .<~ (id_dlns -|-<~ (snd_dlns _L -|-<~ snd_dlns g) .<~ distr_dlns .<~ (id_dlns ><<~ hout_dlns)) .<~ hout_dlns p _ = Left _L g _ = IdF a srcSieve = [0,1,2,3] lnsSieve :: DLens [] Int [] Int lnsSieve = sieve_dlns (-1) getSieve = get lnsSieve srcSieve tgtSieve = [5,1,3] putSieve = put lnsSieve (tgtSieve,srcSieve) dV where dV = Set.fromList [(1,0),(2,1)] checkSieve = testDLens lnsSieve -- * List concatenation data NeList a = NeNil [a] | NeCons a (NeList a) deriving (Eq,Show) type instance HF NeList = HFun [] :+~: HParam :*~: HId instance Hu NeList where hout (NeNil l) = InlF l hout (NeCons x xs) = InrF $ ProdF (IdF x) xs hinn (InlF l) = NeNil l hinn (InrF (ProdF (IdF x) xs)) = NeCons x xs instance FMonoid NeList where fzero = NeNil [] fplus (NeNil xs) (NeNil ys) = NeNil (xs++ys) fplus (NeNil []) y = y fplus (NeNil xs) (NeCons y ys) = fplus (NeNil (xs++[y])) ys fplus x (NeNil []) = x fplus (NeCons x xs) y = NeCons x (fplus xs y) instance Shapely NeList where traverse f = (hinn >< id) . traverse f . (hout >< id) cat_dlns :: DLens ([] :*: []) a [] a cat_dlns = cata_dlns nelist g .<~ ana_dlns nelist h where g = hinn_dlns .<~ (id_dlns -|-<~ ((\/<~) p id_dlns id_dlns)) .<~ coassocr_dlns .<~ (hout_dlns -|-<~ id_dlns) h = (snd_dlns aux -|-<~ assocr_dlns) .<~ distl_dlns .<~ (hout_dlns ><<~ id_dlns) aux _ = ConsF _L p _ = Right _L nelist = ann :: Ann (Fix NeList) srcCat = ProdF [1] [3] tgtCat = [0,1,3,4] lnsCat :: DLens ([] :*: []) Int [] Int lnsCat = cat_dlns getCat = get lnsCat srcCat putCat = put lnsCat (tgtCat,srcCat) dV where dV = Set.fromList [(1,0),(2,1)] checkCat = testDLens lnsCat -- * Tree flatten flatten_dlns :: DLens Tree a [] a flatten_dlns = cata_dlns _L f where f = hinn_dlns .<~ (id_dlns -|-<~ id_dlns ><<~ cat_dlns) srcFlatten = Node 1 (Node 2 Empty Empty) (Node 3 Empty Empty) lnsFlatten :: DLens Tree Int [] Int lnsFlatten = flatten_dlns tgtFlatten = [0,1,2,3] getFlatten = get lnsFlatten srcFlatten putFlatten = put lnsFlatten (tgtFlatten,srcFlatten) dV where dV = Set.fromList [(1,0),(2,1),(3,2)] checkFlatten = testDLens lnsFlatten