{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__ < 806
{-# LANGUAGE TypeInType #-}
#endif
module Data.Vinyl.Lens
( RecElem(..)
, rget, rput, rput', rlens, rlens'
, RElem
, RecSubset(..)
, rsubset, rcast, rreplace
, rdowncast
, RSubset
, REquivalent
, type (∈)
, type (⊆)
, type (≅)
, type (<:)
, type (:~:)
) where
import Data.Kind (Constraint)
import Data.Vinyl.Core
import Data.Vinyl.Functor
import Data.Vinyl.TypeLevel
#if __GLASGOW_HASKELL__ < 806
import Data.Kind
#endif
class (i ~ RIndex r rs, NatToInt i)
=> RecElem record r r' rs rs' (i :: Nat) | r r' rs i -> rs' where
type RecElemFCtx record (f :: k -> *) :: Constraint
type RecElemFCtx record f = ()
rlensC
:: (Functor g, RecElemFCtx record f)
=> (f r -> g (f r'))
-> record f rs
-> g (record f rs')
rgetC
:: (RecElemFCtx record f, r ~ r')
=> record f rs
-> f r
rputC
:: RecElemFCtx record f
=> f r'
-> record f rs
-> record f rs'
type RElem x rs = RecElem Rec x x rs rs
lens
:: Functor f
=> (s -> a)
-> (s -> b -> t)
-> (a -> f b)
-> s
-> f t
lens sa sbt afb s = fmap (sbt s) $ afb (sa s)
{-# INLINE lens #-}
instance RecElem Rec r r' (r ': rs) (r' ': rs) 'Z where
rlensC f (x :& xs) = fmap (:& xs) (f x)
{-# INLINE rlensC #-}
rgetC = getConst . rlensC Const
{-# INLINE rgetC #-}
rputC y = getIdentity . rlensC @_ @r (\_ -> Identity y)
{-# INLINE rputC #-}
instance (RIndex r (s ': rs) ~ 'S i, RecElem Rec r r' rs rs' i)
=> RecElem Rec r r' (s ': rs) (s ': rs') ('S i) where
rlensC f (x :& xs) = fmap (x :&) (rlensC f xs)
{-# INLINE rlensC #-}
rgetC = getConst . rlensC @_ @r @r' Const
{-# INLINE rgetC #-}
rputC y = getIdentity . rlensC @_ @r (\_ -> Identity y)
{-# INLINE rputC #-}
rget :: forall r rs f record.
(RecElem record r r rs rs (RIndex r rs), RecElemFCtx record f)
=> record f rs -> f r
rget = rgetC
rput' :: forall r r' rs rs' record f. (RecElem record r r' rs rs' (RIndex r rs), RecElemFCtx record f)
=> f r' -> record f rs -> record f rs'
rput' = rputC @_ @r @r'
rput :: forall r rs record f. (RecElem record r r rs rs (RIndex r rs), RecElemFCtx record f)
=> f r -> record f rs -> record f rs
rput = rput' @r
rlens' :: forall r r' record rs rs' f g.
(RecElem record r r' rs rs' (RIndex r rs), RecElemFCtx record f, Functor g)
=> (f r -> g (f r')) -> record f rs -> g (record f rs')
rlens' = rlensC
rlens :: forall r record rs f g.
(RecElem record r r rs rs (RIndex r rs), RecElemFCtx record f, Functor g)
=> (f r -> g (f r)) -> record f rs -> g (record f rs)
rlens = rlensC
class is ~ RImage rs ss => RecSubset record rs ss is where
type RecSubsetFCtx record (f :: k -> *) :: Constraint
type RecSubsetFCtx record f = ()
rsubsetC
:: (Functor g, RecSubsetFCtx record f)
=> (record f rs -> g (record f rs))
-> record f ss
-> g (record f ss)
rcastC
:: RecSubsetFCtx record f
=> record f ss
-> record f rs
rcastC = getConst . rsubsetC Const
{-# INLINE rcastC #-}
rreplaceC
:: RecSubsetFCtx record f
=> record f rs
-> record f ss
-> record f ss
rreplaceC rs = getIdentity . rsubsetC (\_ -> Identity rs)
{-# INLINE rreplaceC #-}
rsubset :: forall k rs ss f g record is.
(RecSubset record (rs :: [k]) (ss :: [k]) is,
Functor g, RecSubsetFCtx record f)
=> (record f rs -> g (record f rs)) -> record f ss -> g (record f ss)
rsubset = rsubsetC
rcast :: forall rs ss f record is.
(RecSubset record rs ss is, RecSubsetFCtx record f)
=> record f ss -> record f rs
rcast = rcastC
rreplace :: forall rs ss f record is.
(RecSubset record rs ss is, RecSubsetFCtx record f)
=> record f rs -> record f ss -> record f ss
rreplace = rreplaceC
rdowncast :: (RecApplicative ss, RMap rs, rs ⊆ ss)
=> Rec f rs -> Rec (Maybe :. f) ss
rdowncast = flip rreplace (rpure (Compose Nothing)) . rmap (Compose . Just)
type RSubset = RecSubset Rec
instance RecSubset Rec '[] ss '[] where
rsubsetC = lens (const RNil) const
instance (RElem r ss i , RSubset rs ss is) => RecSubset Rec (r ': rs) ss (i ': is) where
rsubsetC = lens (\ss -> rget ss :& rcastC ss) set
where
set :: Rec f ss -> Rec f (r ': rs) -> Rec f ss
set ss (r :& rs) = rput r $ rreplaceC rs ss
type REquivalent rs ss is js = (RSubset rs ss is, RSubset ss rs js)
type r ∈ rs = RElem r rs (RIndex r rs)
type rs ⊆ ss = RSubset rs ss (RImage rs ss)
type rs ≅ ss = REquivalent rs ss (RImage rs ss) (RImage ss rs)
type rs <: ss = rs ⊆ ss
type rs :~: ss = rs ≅ ss