packages feed

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

-- 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 Effectful ((:>))
import qualified Effectful as Eff
import qualified Effectful.Reader.Static as Eff
import qualified Effectful.State.Static.Local as Eff

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

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

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

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

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

infixr 4 .=

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

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

infixr 4 %=

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

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