sqel-0.0.1.0: lib/Sqel/Class/Mods.hs
module Sqel.Class.Mods where
import Generics.SOP (I (I), NP (Nil, (:*)))
import Prelude hiding (Compose)
import Sqel.Data.Dd (Dd (Dd), DdK (DdK), (:>) ((:>)))
import Sqel.Data.Mods (Mods (Mods), unMods)
class SymNP p ps where
symNP :: p -> NP I ps
instance {-# overlappable #-} (
ps ~ '[p]
) => SymNP p ps where
symNP p =
I p :* Nil
instance (
SymNP p1 ps
) => SymNP (p0 :> p1) (p0 : ps) where
symNP (p0 :> p1) =
I p0 :* symNP p1
instance SymNP (NP I ps) ps where
symNP = id
symMods ::
SymNP p ps =>
p ->
Mods ps
symMods p =
Mods (symNP p)
class MapMod' p ps0 ps1 | p ps0 -> ps1 where
mapMod' :: p -> (p -> p) -> Mods ps0 -> Mods ps1
instance MapMod' p (p : ps) (p : ps) where
mapMod' _ f (Mods (I p :* ps)) =
Mods (I (f p) :* ps)
instance {-# overlappable #-} (
MapMod' p ps0 ps1
) => MapMod' p (a' : ps0) (a' : ps1) where
mapMod' p f (Mods (a' :* ps)) =
Mods (a' :* unMods (mapMod' p f (Mods ps)))
instance MapMod' p '[] '[p] where
mapMod' p f (Mods Nil) =
Mods (I (f p) :* Nil)
amendMod' ::
MapMod' p ps0 ps1 =>
p ->
Mods ps0 ->
Mods ps1
amendMod' p =
mapMod' p id
setMod' ::
MapMod' p ps0 ps1 =>
p ->
Mods ps0 ->
Mods ps1
setMod' p =
mapMod' p (const p)
-- TODO this could map over multiple matching mods
class OverMod' p ps where
overMod' :: (p -> p) -> Mods ps -> Mods ps
instance OverMod' p (p : ps) where
overMod' f (Mods (I p :* ps)) =
Mods (I (f p) :* ps)
instance (
OverMod' p ps
) => OverMod' p (a' : ps) where
overMod' f (Mods (a' :* ps)) =
Mods (a' :* unMods (overMod' f (Mods ps)))
instance OverMod' p '[] where
overMod' _ (Mods Nil) =
Mods Nil
class CMapMod' c p0 p p1 ps0 ps1 | ps0 p0 p1 -> p ps1 where
cmapMod' :: p0 -> (c p p1 => p -> p1) -> Mods ps0 -> Mods ps1
instance (
c p p1
) => CMapMod' c p0 p p1 (p : ps) (p1 : ps) where
cmapMod' _ f (Mods (I p :* ps)) =
Mods (I (f p) :* ps)
instance (
CMapMod' c p0 p p1 ps0 ps1
) => CMapMod' c p0 p p1 (a' : ps0) (a' : ps1) where
cmapMod' p f (Mods (a' :* ps)) =
Mods (a' :* unMods (cmapMod' @c @p0 @p @p1 @ps0 @ps1 p f (Mods ps)))
instance CMapMod' c p0 p1 p1 '[] '[p0] where
cmapMod' p _ (Mods Nil) =
Mods (I p :* Nil)
type GetMod :: Constraint -> Type -> [Type] -> Constraint
class GetMod c p ps where
getMod :: (c => p) -> Mods ps -> p
instance c => GetMod c p '[] where
getMod f (Mods Nil) = f
instance GetMod c p (p : ps) where
getMod _ (Mods (I p :* _)) = p
class AddMod p s0 s1 | p s0 -> s1 where
addMod :: p -> Dd s0 -> Dd s1
instance AddMod p ('DdK sel ps a s) ('DdK sel (p : ps) a s) where
addMod p (Dd sel (Mods ps) s) =
Dd sel (Mods (I p :* ps)) s
instance {-# overlappable #-} (
GetMod c p ps
) => GetMod c p (a' : ps) where
getMod f (Mods (_ :* ps)) =
getMod @c f (Mods ps)
class MapMod p s0 s1 | p s0 -> s1 where
mapMod :: p -> (p -> p) -> Dd s0 -> Dd s1
instance (
MapMod' p ps0 ps1
) => MapMod p ('DdK sel ps0 a s0) ('DdK sel ps1 a s0) where
mapMod p f (Dd sel ps0 s) =
Dd sel (mapMod' p f ps0) s
class OverMod p s where
overMod :: (p -> p) -> Dd s -> Dd s
instance (
OverMod' p ps
) => OverMod p ('DdK sel ps a s0) where
overMod f (Dd sel ps s) =
Dd sel (overMod' f ps) s
class CMapMod c p0 p p1 s0 s1 | s0 p0 p1 -> p s1 where
cmapMod :: p0 -> (c p p1 => p -> p1) -> Dd s0 -> Dd s1
instance (
CMapMod' c p0 p p1 ps0 ps1
) => CMapMod c p0 p p1 ('DdK sel ps0 a s0) ('DdK sel ps1 a s0) where
cmapMod p0 f (Dd sel ps0 s) =
Dd sel (cmapMod' @c @_ @_ @p1 p0 f ps0) s
-- TODO this appends the mod if it is missing, while it should prepend it to preserve the order of effects.
amendMod ::
MapMod p s0 s1 =>
p ->
Dd s0 ->
Dd s1
amendMod p =
mapMod p id
setMod ::
MapMod p s0 s1 =>
p ->
Dd s0 ->
Dd s1
setMod p =
mapMod p (const p)
type OptMod :: Type -> [Type] -> Type -> Constraint
class OptMod p ps res | ps p -> res where
optMod :: Mods ps -> res
instance OptMod p '[] () where
optMod (Mods Nil) = ()
instance OptMod p (p : ps) p where
optMod (Mods (I p :* _)) = p
instance {-# overlappable #-} (
OptMod p ps p1
) => OptMod p (p0 : ps) p1 where
optMod (Mods (_ :* ps)) = optMod @p (Mods ps)
type MaybeMod :: Type -> [Type] -> Constraint
class MaybeMod p ps where
maybeMod :: Mods ps -> Maybe p
instance MaybeMod p '[] where
maybeMod (Mods Nil) = Nothing
instance MaybeMod p (p : ps) where
maybeMod (Mods (I p :* _)) = Just p
instance {-# overlappable #-} (
MaybeMod p ps
) => MaybeMod p (p0 : ps) where
maybeMod (Mods (_ :* ps)) = maybeMod @p (Mods ps)