{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE ExistentialQuantification #-} -- | This module containt the type definitions necessary to build a Nomic rule. module Language.Nomyx.Expression where import Data.Typeable import Data.Time import Control.Applicative hiding (Const) import Data.Lens.Template import Control.Monad.Error type PlayerNumber = Int type PlayerName = String type RuleNumber = Int type RuleName = String type RuleDesc = String type RuleText = String type RuleCode = String type EventNumber = Int type EventName = String type VarName = String type Code = String type OutputNumber = Int type InputNumber = Int -- * Nomyx Expression data Eff = Effect | NoEffect type Effect = 'Effect type NoEffect = 'NoEffect -- | A Nomex (Nomyx Expression) allows the players to write rules. -- within the rules, you can access and modify the state of the game. type Nomex = Exp Effect -- | A NomexNE (Nomyx Expression No Effect) is a specialisation of the type that guaranties -- that the instructions will have no effects. type NomexNE = Exp NoEffect data Exp :: Eff -> * -> * where --Variables management NewVar :: (Typeable a, Show a) => VarName -> a -> Nomex (Maybe (V a)) ReadVar :: (Typeable a, Show a) => V a -> NomexNE (Maybe a) WriteVar :: (Typeable a, Show a) => V a -> a -> Nomex Bool DelVar :: (V a) -> Nomex Bool --Events management OnEvent :: (Typeable e, Show e) => Event e -> ((EventNumber, e) -> Nomex ()) -> Nomex EventNumber DelEvent :: EventNumber -> Nomex Bool SendMessage :: (Typeable a, Show a) => Msg a -> a -> Nomex () --Rules management ProposeRule :: RuleInfo -> Nomex Bool ActivateRule :: RuleNumber -> Nomex Bool RejectRule :: RuleNumber -> Nomex Bool AddRule :: RuleInfo -> Nomex Bool ModifyRule :: RuleNumber -> RuleInfo -> Nomex Bool GetRules :: NomexNE [RuleInfo] --Players management GetPlayers :: NomexNE [PlayerInfo] SetPlayerName :: PlayerNumber -> PlayerName -> Nomex Bool DelPlayer :: PlayerNumber -> Nomex Bool --Outputs NewOutput :: Maybe PlayerNumber -> NomexNE String -> Nomex OutputNumber GetOutput :: OutputNumber -> NomexNE (Maybe String) UpdateOutput :: OutputNumber -> NomexNE String -> Nomex Bool DelOutput :: OutputNumber -> Nomex Bool --Mileacenous SetVictory :: NomexNE [PlayerNumber] -> Nomex () CurrentTime :: NomexNE UTCTime SelfRuleNumber :: NomexNE RuleNumber --Monadic bindings Return :: a -> Exp e a Bind :: Exp e a -> (a -> Exp e b) -> Exp e b ThrowError :: String -> Exp Effect a CatchError :: Nomex a -> (String -> Nomex a) -> Nomex a LiftEffect :: NomexNE a -> Nomex a Simu :: Nomex a -> NomexNE Bool -> NomexNE Bool instance Typeable1 (Exp NoEffect) where typeOf1 _ = mkTyConApp (mkTyCon3 "main" "Language.Nomyx.Expression" "Exp NoEffect") [] instance Typeable1 (Exp Effect) where typeOf1 _ = mkTyConApp (mkTyCon3 "main" "Language.Nomyx.Expression" "Exp Effect") [] liftEffect :: NomexNE a -> Nomex a liftEffect = LiftEffect instance Monad (Exp a) where return = Return (>>=) = Bind instance Functor (Exp a) where fmap f e = Bind e $ Return . f instance Applicative (Exp a) where pure = Return f <*> a = do f' <- f a' <- a return $ f' a' instance MonadError String Nomex where throwError = ThrowError catchError = CatchError instance Typeable a => Show (Exp NoEffect a) where show e = "<" ++ (show $ typeOf e) ++ ">" instance Typeable a => Show (Exp Effect a) where show e = "<" ++ (show $ typeOf e) ++ ">" instance (Typeable a, Typeable b) => Show (a -> b) where show e = '<' : (show . typeOf) e ++ ">" -- * Variables -- | a container for a variable name and type data V a = V {varName :: String} deriving Typeable -- * Events -- | Composable events data Event a where SumEvent :: Event a -> Event a -> Event a -- The first event to fire will be returned AppEvent :: Event (a -> b) -> Event a -> Event b -- Both events should fire, and then the result is returned PureEvent :: a -> Event a -- Create a fake event. The result is useable with no delay. EmptyEvent :: Event a -- An event that is never fired. BaseEvent :: (Typeable a) => Field a -> Event a -- Embed a base event deriving Typeable -- | Base events data Field a where Input :: Maybe InputNumber -> PlayerNumber -> String -> (InputForm a) -> Field a Player :: Player -> Field PlayerInfo RuleEv :: RuleEvent -> Field RuleInfo Time :: UTCTime -> Field UTCTime Message :: Msg a -> Field a Victory :: Field VictoryCond deriving Typeable -- | Type agnostic base event data SomeField = forall a. (Typeable a) => SomeField (Field a) -- | Events parameters data Player = Arrive | Leave deriving (Typeable, Show, Eq) data RuleEvent = Proposed | Activated | Rejected | Added | Modified | Deleted deriving (Typeable, Show, Eq) data Msg m = Msg String deriving (Typeable, Show) -- | Input forms data InputForm a where Text :: InputForm String TextArea :: InputForm String Button :: InputForm () Radio :: (Show a, Eq a) => [(a, String)] -> InputForm a Checkbox :: (Show a, Eq a) => [(a, String)] -> InputForm [a] deriving Typeable deriving instance Show (InputForm a) deriving instance Show (Field a) deriving instance Show SomeField deriving instance Eq (Field e) deriving instance Eq (InputForm e) deriving instance Eq (Msg e) instance Functor Event where fmap f a = pure f <*> a instance Applicative Event where pure = PureEvent (<*>) = AppEvent instance Alternative Event where (<|>) = SumEvent empty = EmptyEvent -- * Rule -- | Type of a rule function. type Rule = Nomex () -- | An informationnal structure about a rule data RuleInfo = RuleInfo { _rNumber :: RuleNumber, -- number of the rule (must be unique) TO CHECK _rName :: RuleName, -- short name of the rule _rDescription :: String, -- description of the rule _rProposedBy :: PlayerNumber, -- player proposing the rule _rRuleCode :: Code, -- code of the rule as a string _rRule :: Rule, -- function representing the rule (interpreted from rRuleCode) _rStatus :: RuleStatus, -- status of the rule _rAssessedBy :: Maybe RuleNumber} -- which rule accepted or rejected this rule deriving (Typeable, Show) instance Eq RuleInfo where (RuleInfo {_rNumber=r1}) == (RuleInfo {_rNumber=r2}) = r1 == r2 instance Ord RuleInfo where (RuleInfo {_rNumber=r1}) <= (RuleInfo {_rNumber=r2}) = r1 <= r2 -- | the status of a rule. data RuleStatus = Active -- Active rules forms the current Constitution | Pending -- Proposed rules | Reject -- Rejected rules deriving (Eq, Show, Typeable) -- * Player -- | informations on players data PlayerInfo = PlayerInfo { _playerNumber :: PlayerNumber, _playerName :: String, _playAs :: Maybe PlayerNumber} deriving (Eq, Typeable, Show) instance Ord PlayerInfo where h <= g = (_playerNumber h) <= (_playerNumber g) -- * Victory data VictoryCond = VictoryCond RuleNumber (NomexNE [PlayerNumber]) deriving (Show, Typeable) partial :: String -> Nomex (Maybe a) -> Nomex a partial s nm = do m <- nm case m of Just a -> return a Nothing -> throwError s concatMapM :: (Monad m) => (a -> m [b]) -> [a] -> m [b] concatMapM f xs = liftM concat (mapM f xs) $( makeLenses [''RuleInfo, ''PlayerInfo] )