packages feed

axel-0.0.11: src/Axel/Eff/Lens.hs

{-# LANGUAGE GADTs #-}

-- NOTE Inspired by `fused-effects-lens`.
module Axel.Eff.Lens where

import Axel.Prelude

import Control.Lens
  ( ASetter
  , ASetter'
  , Const(Const)
  , Const
  , Getting
  , LensLike'
  , (<>~)
  , getConst
  , over
  , set
  )
import qualified Control.Lens.Getter as Lens (view, views)

import Data.Profunctor.Unsafe (Profunctor(( #. )))

import qualified Polysemy as Sem
import qualified Polysemy.Reader as Sem
import qualified Polysemy.State as Sem

{-# INLINE view #-}
view :: (Sem.Member (Sem.Reader s) effs) => Getting a s a -> Sem.Sem effs a
view l = Sem.asks $ getConst #. l Const

{-# INLINE views #-}
views ::
     (Sem.Member (Sem.Reader s) effs)
  => LensLike' (Const r) s a
  -> (a -> r)
  -> Sem.Sem effs r
views l f = Sem.asks $ getConst #. l (Const #. f)

{-# INLINE use #-}
use :: (Sem.Member (Sem.State s) effs) => Getting a s a -> Sem.Sem effs a
use = Sem.gets . Lens.view

{-# INLINE uses #-}
uses ::
     (Sem.Member (Sem.State s) effs)
  => LensLike' (Const r) s a
  -> (a -> r)
  -> Sem.Sem effs r
uses l f = Sem.gets $ Lens.views l f

{-# INLINE assign #-}
assign ::
     (Sem.Member (Sem.State s) effs) => ASetter s s a b -> b -> Sem.Sem effs ()
assign l b = Sem.modify $ set l b

infixr 4 .=

{-# INLINE (.=) #-}
(.=) ::
     (Sem.Member (Sem.State s) effs) => ASetter s s a b -> b -> Sem.Sem effs ()
(.=) = assign

{-# INLINE modifying #-}
modifying ::
     (Sem.Member (Sem.State s) effs)
  => ASetter s s a b
  -> (a -> b)
  -> Sem.Sem effs ()
modifying l f = Sem.modify $ over l f

infixr 4 %=

{-# INLINE (%=) #-}
(%=) ::
     (Sem.Member (Sem.State s) effs)
  => ASetter s s a b
  -> (a -> b)
  -> Sem.Sem effs ()
(%=) = modifying

{-# INLINE (<>=) #-}
(<>=) ::
     (Sem.Member (Sem.State s) effs, Monoid a)
  => ASetter' s a
  -> a
  -> Sem.Sem effs ()
l <>= a = Sem.modify $ l <>~ a