{-# 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         #-}
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
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 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