packages feed

pandora-0.5.6: Pandora/Paradigm/Inventory/Some/Optics.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE UndecidableInstances #-}
module Pandora.Paradigm.Inventory.Some.Optics where

import Pandora.Core.Functor (type (<))
import Pandora.Core.Impliable (Impliable (Arguments, imply))
import Pandora.Core.Interpreted (Interpreted (Primary, run, unite, (<~)))
import Pandora.Pattern.Semigroupoid (Semigroupoid ((.)))
import Pandora.Pattern.Category (Category (identity, (<--), (<---), (<----), (<-----), (<-------)))
import Pandora.Pattern.Kernel (constant)
import Pandora.Pattern.Functor.Covariant (Covariant ((<-|-), (<-|-|-)))
import Pandora.Pattern.Functor.Invariant (Invariant ((<!<)))
import Pandora.Pattern.Functor.Semimonoidal (Semimonoidal (mult))
import Pandora.Pattern.Functor.Representable (Representable (Representation, (<#>), tabulate))
import Pandora.Pattern.Transformation.Liftable (Liftable (lift))
import Pandora.Pattern.Transformation.Lowerable (Lowerable (lower))
import Pandora.Pattern.Object.Setoid (Setoid ((?=)))
import Pandora.Paradigm.Inventory.Ability.Gettable (Gettable (Getting, get))
import Pandora.Paradigm.Inventory.Ability.Settable (Settable (Setting, set))
import Pandora.Paradigm.Inventory.Ability.Modifiable (Modifiable (Modification, modify))
import Pandora.Pattern.Operation.Product ((:*:) ((:*:)))
import Pandora.Pattern.Operation.Exponential (type (-->), (%))
import Pandora.Paradigm.Algebraic (Pointable, point, extract, (>-||---))
import Pandora.Paradigm.Primary.Functor.Exactly (Exactly (Exactly))
import Pandora.Paradigm.Primary.Functor.Maybe (Maybe (Just, Nothing))
import Pandora.Pattern.Morphism.Flip (Flip (Flip))
import Pandora.Pattern.Morphism.Straight (Straight (Straight))
import Pandora.Paradigm.Inventory.Some.Store (Store (Store), position, look, retrofit)
import Pandora.Paradigm.Schemes.P_Q_T (P_Q_T (P_Q_T))
import Pandora.Paradigm.Structure.Ability.Monotonic (resolve)

infixr 6 @>>>
infixl 7 #=@

type Lens = P_Q_T (->) Store

instance Invariant (Flip (Lens available) tgt) where
	f <!< g = \(Flip (P_Q_T lens)) -> Flip . P_Q_T <------- g >-||--- f <-|-|- lens

type family Convex lens where
	Convex Lens = Lens Exactly

instance Semigroupoid (Lens Exactly) where
	(.) :: Convex Lens between target -> Convex Lens source between -> Convex Lens source target
	P_Q_T to . P_Q_T from = P_Q_T <-- \source ->
		let (Exactly between :*: bs) = run <-- from source in
		let (Exactly target :*: tb) = run <-- to between in
		Store <--- Exactly target :*: bs . Exactly . tb

instance Category (Lens Exactly) where
	identity :: Convex Lens source source
	identity = imply @(Convex Lens _ _) identity ((%) constant)

instance Semimonoidal (-->) (:*:) (:*:) (Lens Exactly source) where
	mult = Straight <-- \(P_Q_T x :*: P_Q_T y) -> P_Q_T <-- \source ->
		let Store (Exactly xt :*: ixts) :*: Store (Exactly yt :*: _) = x source :*: y source in
		Store <--- Exactly (xt :*: yt) :*: \(Exactly (xt_ :*: yt_)) ->
			let modified = ixts <-- Exactly xt_ in
			extract <--- run <-- y modified <--- Exactly yt_

instance Impliable (P_Q_T (->) Store Exactly source target) where
	type Arguments (P_Q_T (->) Store Exactly source target) =
		(source -> target) -> (source -> target -> source) -> Lens Exactly source target
	imply getter setter = P_Q_T <-- \source -> Store <--- Exactly (getter source) :*: setter source . extract

type family Obscure lens where
	Obscure Lens = Lens Maybe

instance Impliable (P_Q_T (->) Store Maybe source target) where
	type Arguments (P_Q_T (->) Store Maybe source target) =
		(source -> Maybe target) -> (source -> Maybe target -> source) -> Lens Maybe source target
	imply getter setter = P_Q_T <-- \source -> Store <--- getter source :*: setter source

-- This type of lens leave whole structure untouched if we set target = Nothing
instance Semigroupoid (Lens Maybe) where
	(.) :: Obscure Lens between target -> Obscure Lens source between -> Obscure Lens source target
	P_Q_T to . P_Q_T from = P_Q_T <-- \source -> case run <-- from source of
		Nothing :*: _ -> Store <--- Nothing :*: constant source
		Just between :*: mbs -> case run <-- to between of
			Nothing :*: _ -> Store <--- Nothing :*: constant source
			Just target :*: mtb -> Store <--- Just target :*: mbs . Just . mtb

instance Category (Lens Maybe) where
	identity :: Obscure Lens source source
	identity = imply @(Obscure Lens _ _) <-- Just <-- resolve identity

-- Lens as natural transformation
type (#=@) source target available = forall a . Lens available (source a) (target a)

type (@>>>) source target = forall a . Lens target (source a) a

-- | Representable based lens
represent :: forall t a . (Representable t, Setoid (Representation t)) => Representation t -> Convex Lens (t a) a
represent r = imply @(Convex Lens (t a) a) (r <#>) (\source target -> tabulate <-- \r' -> r' ?= r <----- target <----- r' <#> source)

class Lensic previous next where
	type Lensally previous next :: * -> *
	(>>>) :: Lens previous source between -> Lens next between target -> Lens (Lensally previous next) source target

instance Semigroupoid (Lens t) => Lensic t t where
	type Lensally t t = t
	x >>> y = y . x

instance Lensic Maybe Exactly where
	type Lensally Maybe Exactly = Maybe
	P_Q_T from >>> P_Q_T to = P_Q_T <-- \source -> case run <-- from source of
		Nothing :*: _ -> Store <--- Nothing :*: \_ -> source
		Just between :*: mbs -> case run <-- to between of
			Exactly target :*: itb -> Store <--- Just target :*: \mt -> mbs <---- itb . Exactly <-|- mt

instance Lensic Exactly Maybe where
	type Lensally Exactly Maybe = Maybe
	P_Q_T from >>> P_Q_T to = P_Q_T <-- \source -> case run <-- from source of
		Exactly between :*: ibs -> case run <-- to between of
			Just target :*: mtb -> Store <--- Just target :*: ibs . Exactly . mtb
			Nothing :*: _ -> Store <--- Nothing :*: constant source

instance Gettable (Lens Exactly) where
	type instance Getting (Lens Exactly) source target = Lens Exactly source target -> source -> target
	get lens source = extract @Exactly . position @_ @(Store _) <-- lens <~ source

instance Gettable (Lens Maybe) where
	type instance Getting (Lens Maybe) source target = Lens Maybe source target -> source -> Maybe target
	get lens source = position @_ @(Store _) <-- lens <~ source

instance Pointable t => Settable (Lens t) where
	type instance Setting (Lens t) source target = target -> Lens t source target -> source -> source
	set new lens source = look @(t _) <-- point new <-- lens <~ source

instance (Gettable (Lens t), Covariant (->) (->) t, Pointable t) => Modifiable (Lens t) where
	type instance Modification (Lens t) source target = (target -> target) -> Lens t source target -> source -> source
	modify f lens source = extract . retrofit (f <-|-) <-- lens <~ source

view :: Lens i source target -> source -> i target
view lens source = position @_ @(Store _) <-- lens <~ source

replace :: forall i source target . i target -> Lens i source target -> source -> source
replace new lens source = look @(i _) <-- new <-- lens <~ source

mutate :: (i target -> i target) -> Lens i source target -> source -> source
mutate mut lens source = extract . retrofit mut <-- lens <~ source

transwrap :: (Covariant (->) (->) u, Liftable (->) t, Lowerable (->) t) => Lens u < t u e < e
transwrap = P_Q_T <-- \origin -> Store <--- lower origin :*: lift

primary :: Interpreted (->) t => Lens Exactly < t a < Primary t a
primary = P_Q_T <-- \origin -> Store <--- Exactly (run origin) :*: unite . extract