packages feed

composite-lens-extra-0.1.0.0: src/Composite/Lens/Extra.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE TypeOperators       #-}
{-# LANGUAGE ViewPatterns        #-}

module Composite.Lens.Extra
  (
    rlensS,
    rlensS',
    rlensS'',
  )
where

import           Composite.Record           (Rec, Record, getVal, (:->) (Val))
import qualified Control.Lens               as L
import           Data.Functor.Contravariant (Contravariant (contramap))
import qualified Data.Vinyl                 as Vinyl
import           Data.Vinyl.TypeLevel       (RIndex)

-- | Type changing lens over a `Record` field.
--
-- @since 0.0.1.0
rlensS ::
  forall p p' s s' a b g rs rs'.
  ( (p ~ (s :-> a)),
    (p' ~ (s' :-> b)),
    Vinyl.RecElem
      Rec
      (s :-> a)
      (s' :-> b)
      rs
      rs'
      (RIndex (s :-> a) rs),
    Functor g
  ) =>
  (a -> g b) ->
  Record rs ->
  g (Record rs')
rlensS f = Vinyl.rlens' @p @p' $ \(L.Identity (getVal -> a)) -> L.Identity . Val <$> f a

-- | Type changing lens over a `Rec f` (Covariant).
--
-- @since 0.0.1.0
rlensS' ::
  forall p p' s s' a b f g rs rs'.
  ( (p ~ (s :-> a)),
    (p' ~ (s' :-> b)),
    Vinyl.RecElem
      Rec
      (s :-> a)
      (s' :-> b)
      rs
      rs'
      (Data.Vinyl.TypeLevel.RIndex (s :-> a) rs),
    Functor f,
    Functor g
  ) =>
  (f a -> g (f b)) ->
  Rec f rs ->
  g (Rec f rs')
rlensS' f = Vinyl.rlens' @p @p' $ \(fmap getVal -> a) -> fmap Val <$> f a

-- | Type changing lens over a `Rec f` (Contravariant).
--
-- @since 0.0.1.0
rlensS'' ::
  forall p p' s s' a b f g rs rs'.
  ( (p ~ (s :-> a)),
    (p' ~ (s' :-> b)),
    Vinyl.RecElem
      Rec
      (s :-> a)
      (s' :-> b)
      rs
      rs'
      (Data.Vinyl.TypeLevel.RIndex (s :-> a) rs),
    Contravariant f,
    Functor g
  ) =>
  (f a -> g (f b)) ->
  Rec f rs ->
  g (Rec f rs')
rlensS'' f = Vinyl.rlens' @p @p' $ \(contramap Val -> a) -> contramap getVal <$> f a