-- | Provides framework for "phased" data. This is a generalization of
-- the "Higher-kinded data" approach where instead of merely annotating a
-- data type with some constructor e.g.
--
-- @
-- data Foo f = MkFoo
--   { bar :: f Bool,
--     baz :: f String,
--     ...
--   }
-- @
--
-- we use a type family:
--
-- @
-- data Foo s = MkFoo
--   { bar :: Fam1 s,
--     baz :: Fam2 s,
--   ...
--   }
-- @
--
-- Not only does this allow fields to vary independently, it also means
-- we can avoid clunky wrappers like @Identity@.
--
-- We do this so that we can represent data that "evolves" e.g. we may
-- initially parse a data type as Foo1 (phase 1) but then further process
-- this data type into Foo2 (phase 2). Using this phase approach avoids
-- duplication of constructors and fields.
module Charon.Runner.Phase
  ( Phase (..),
    AdvancePhase (..),
    MaybePhaseF,
  )
where

import Charon.Prelude

-- | Index for data that has a "phased" evolution.
data Phase
  = Phase1
  | Phase2
  deriving stock
    ( Phase -> Phase -> Bool
(Phase -> Phase -> Bool) -> (Phase -> Phase -> Bool) -> Eq Phase
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Phase -> Phase -> Bool
== :: Phase -> Phase -> Bool
$c/= :: Phase -> Phase -> Bool
/= :: Phase -> Phase -> Bool
Eq,
      Int -> Phase -> ShowS
[Phase] -> ShowS
Phase -> String
(Int -> Phase -> ShowS)
-> (Phase -> String) -> ([Phase] -> ShowS) -> Show Phase
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Phase -> ShowS
showsPrec :: Int -> Phase -> ShowS
$cshow :: Phase -> String
show :: Phase -> String
$cshowList :: [Phase] -> ShowS
showList :: [Phase] -> ShowS
Show
    )

-- | Advances phased data.
class AdvancePhase a where
  -- | The next phase.
  type NextPhase a

  -- | Advances the data.
  advancePhase :: a -> NextPhase a

-- | Type family for the common case of evolving an optional type @Maybe a@
-- into a definite @a@ (i.e. after default substitution).
type MaybePhaseF :: Phase -> Type -> Type
type family MaybePhaseF s a where
  MaybePhaseF Phase1 a = Maybe a
  MaybePhaseF Phase2 a = a