module Lang.Hask.Monads where

import FP
import MAAM hiding (Time(..))
import Lang.Hask.Semantics
import Lang.Hask.Execution
import Lang.Hask.Pretty ()

type PSΣ' ν   = (ID :.: ListSetWithTop) :.: (,) (𝒮 ν  )

newtype PSΣ ν   a = PSΣ { runPSΣ :: ListSetWithTop (a, 𝒮 ν  ) } deriving (PartialOrder, Bot, Join, JoinLattice)
instance Morphism2 (PSΣ ν  ) (PSΣ' ν  )  where morph2 = Compose . Compose . ID . map swap . runPSΣ
instance Morphism2 (PSΣ' ν  ) (PSΣ ν  ) where morph2 = PSΣ . map swap . unID . unCompose . unCompose
instance (TimeC  ) => Inject (PSΣ ν  ) where inj = PSΣ . inj . (,bot)
instance Isomorphism2 (PSΣ ν  ) (PSΣ' ν  )

newtype PSΣ𝒫 ν   a = PSΣ𝒫 { runPSΣ𝒫 :: SetWithTop (a, 𝒮 ν  ) }
  deriving (PartialOrder, Bot, Join, JoinLattice, Difference, Pretty)
instance (Ord (ν  ), Ord , Ord , Ord a) => Morphism (PSΣ ν   a) (PSΣ𝒫 ν   a) where
  morph (PSΣ a𝓈s) = PSΣ𝒫 $ setFromListWithTop a𝓈s
instance (Ord (ν  ), Ord , Ord , Ord a) => Morphism (PSΣ𝒫 ν   a) (PSΣ ν   a) where
  morph (PSΣ𝒫 a𝓈s) = PSΣ $ listFromSetWithTop a𝓈s
instance (Ord (ν  ), Ord , Ord , Ord a) => Isomorphism (PSΣ ν   a) (PSΣ𝒫 ν   a)

newtype PS ν   a = FSPS 
  { runPS :: IsoMonadStep (PSΣ ν  ) (PSΣ' ν  ) 
                 (StateT (𝒮 ν  ) (ListSetWithTopT ID)) a 
  } deriving 
    ( Unit, Functor, Product, Applicative, Bind, Monad
    , MonadBot, MonadPlus, MonadTop
    , MonadState (𝒮 ν  )
    , MonadStep (PSΣ ν  )
    )
instance (TimeC  , ValC ν  ) => Analysis ν   (PS ν  )
instance (TimeC  , Ord (ν  )) => Execution (PSΣ𝒫 ν  ) (PSΣ ν  ) (PS ν  )
psm :: P  -> P  -> P ν -> P (PS ν  )
psm P P P = P