{-# LANGUAGE RankNTypes #-}

-- | Lenses for easily getting and setting values.
module Strive.Lenses
  ( Lens,
    get,
    set,
    update,
  )
where

import Data.Functor.Constant (Constant (Constant), getConstant)
import Data.Functor.Identity (Identity (Identity), runIdentity)

-- | A lens for a record.
type Lens a b = forall f. (Functor f) => (b -> f b) -> a -> f a

-- | Get a field from a record.
get :: Lens a b -> a -> b
get :: forall a b. Lens a b -> a -> b
get Lens a b
lens = Constant b a -> b
forall {k} a (b :: k). Constant a b -> a
getConstant (Constant b a -> b) -> (a -> Constant b a) -> a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (b -> Constant b b) -> a -> Constant b a
Lens a b
lens b -> Constant b b
forall {k} a (b :: k). a -> Constant a b
Constant

-- | Set a field in a record.
set :: Lens a b -> b -> a -> a
set :: forall a b. Lens a b -> b -> a -> a
set Lens a b
lens b
x = Lens a b -> (b -> b) -> a -> a
forall a b. Lens a b -> (b -> b) -> a -> a
update (b -> f b) -> a -> f a
Lens a b
lens (b -> b -> b
forall a b. a -> b -> a
const b
x)

-- | Update a field in a record
update :: Lens a b -> (b -> b) -> a -> a
update :: forall a b. Lens a b -> (b -> b) -> a -> a
update Lens a b
lens b -> b
f = Identity a -> a
forall a. Identity a -> a
runIdentity (Identity a -> a) -> (a -> Identity a) -> a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (b -> Identity b) -> a -> Identity a
Lens a b
lens (b -> Identity b
forall a. a -> Identity a
Identity (b -> Identity b) -> (b -> b) -> b -> Identity b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> b
f)