vinyl-plus-0.1.0.0: src/Data/Vinyl/Optic/Plain/Class.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
module Data.Vinyl.Optic.Plain.Class where
import Data.Profunctor.Choice (Choice)
import Data.Vinyl.Core
import Data.Vinyl.Plus.Internal (prism')
import Data.Vinyl.Plus.TypeLevel
import Data.Vinyl.TypeLevel
import Data.Vinyl.Types
-- | This is a drop-in replacement for the 'RElem' class from @Data.Vinyl.Lens@.
-- The functions it provides work on 'CoRec's instead of 'Rec's.
-- It also provides a lifting function 'clift', which has no
-- equivalent operation on 'Rec's.
-- If 'CoRec' were merged into @vinyl@, this typeclass could be
-- eliminated, and its methods could be added to 'RElem'.
class i ~ RIndex r rs => RElem (r :: k) (rs :: [k]) (i :: Nat) where
-- | We can get a prism for getting and setting values in a 'CoRec'. Morally,
--
-- > cprism :: Prism' (CoRec f rs) (f r)
cprism :: (Choice p, Applicative g) => proxy r -> p (f r) (g (f r)) -> p (CoRec f rs) (g (CoRec f rs))
-- | Get a value from a 'CoRec'. Note that, unlike 'rget',
-- this function may not find the requested element, so
-- the result is wrapped in 'Maybe'.
cget :: proxy r -> CoRec f rs -> Maybe (f r)
-- | If the element in the 'CoRec' is of a certain type,
-- modify it. Otherwise, leave the 'CoRec' unchanged.
cmodify :: (f r -> f r) -> CoRec f rs -> CoRec f rs
-- | If the element in the 'CoRec' is of a certain type,
-- replace it. This function is provided for symmetry
-- with 'rput', but it is not typically useful.
-- Usually, 'clift' is more useful.
cput :: f r -> CoRec f rs -> CoRec f rs
-- | Lift an element into a 'CoRec'.
clift :: f r -> CoRec f rs
instance (r ~ s) => RElem r (s ': rs) 'Z where
cprism p = prism' clift (cget p)
clift = CoRecHere
cget _ (CoRecHere v) = Just v
cget _ (CoRecThere _) = Nothing
cput v (CoRecHere _) = CoRecHere v
cput _ r@(CoRecThere _) = r
cmodify f (CoRecHere v) = CoRecHere (f v)
cmodify _ r@(CoRecThere _) = r
instance (RIndex r (s ': rs) ~ 'S i, RElem r rs i) => RElem r (s ': rs) ('S i) where
cprism p = prism' clift (cget p)
clift v = CoRecThere (clift v)
cget _ (CoRecHere _) = Nothing
cget proxy (CoRecThere c) = cget proxy c
cput _ r@(CoRecHere _) = r
cput v (CoRecThere r) = CoRecThere (cput v r)
cmodify _ r@(CoRecHere _) = r
cmodify f (CoRecThere r) = CoRecThere (cmodify f r)
class is ~ RImage sub super => RSubset (sub :: [k]) (super :: [k]) is where
-- | Upcast a 'CoRec' to another 'CoRec' that could be
-- inhabited by additional types.
ccast :: CoRec f sub -> CoRec f super
instance RSubset '[] super '[] where
ccast _ = error "CSubset: an empty CoRec is not possible"
instance (RElem r super i , RSubset sub super is) => RSubset (r ': sub) super (i ': is) where
ccast (CoRecHere v) = clift v
ccast (CoRecThere cr) = ccast cr
-- | Two record types are equivalent when they are subtypes of each other.
type REquivalent rs ss is js = (RSubset rs ss is, RSubset ss rs js)
-- | A shorthand for 'RElem' which supplies its index.
type RElem' r rs = RElem r rs (RIndex r rs)
-- | An infix operator for 'RMember\''.
type r ∈ rs = RElem' r rs
-- | A shorthand for 'RSubset' which supplies its image.
type RSubset' rs ss = RSubset rs ss (RImage rs ss)
-- | An infix operator for 'RSubset\''
type rs ⊆ ss = RSubset' rs ss
-- | A shorthand for 'REquivalent' which supplies its images.
type REquivalent' rs ss = REquivalent rs ss (RImage rs ss) (RImage ss rs)
-- | An infix operator for 'REquivalent\''
type rs ≅ ss = REquivalent' rs ss
-- | A non-unicode equivalent of @(⊆)@.
type rs <: ss = rs ⊆ ss
-- | A non-unicode equivalent of @(≅)@.
type rs :~: ss = rs ≅ ss
-- type CElem r rs = CElemX r rs (RIndex r rs)
-- type CSubset sub super = CSubsetX sub super (RImage sub super)
-- example :: CoRec Maybe '[Bool,Int,Double]
-- example = clift (Just (4 :: Int))
--
-- example2 :: CoRec Maybe '[Bool,Int] -> CoRec Maybe '[Int,Bool,Char]
-- example2 = ccast
--
-- example3 :: Maybe Int -> CoRec Maybe '[Bool,Int] -> CoRec Maybe '[Bool,Int]
-- example3 = cput
--
-- example4 :: CoRec Maybe '[Bool,Int] -> Maybe (Maybe Int)
-- example4 = cget (Nothing :: Maybe Int)