Advertisement
Guest User

Untitled

a guest
Jul 26th, 2019
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  2. {-# LANGUAGE ScopedTypeVariables #-}
  3. {-# LANGUAGE MultiParamTypeClasses #-}
  4. {-# LANGUAGE AllowAmbiguousTypes #-}
  5. {-# LANGUAGE FlexibleContexts #-}
  6. {-# LANGUAGE TypeApplications #-}
  7.  
  8. import Control.Monad.Reader (ReaderT, runReaderT)
  9. import Control.Monad.State  (StateT, evalStateT)
  10. import Control.Monad        (void)
  11.  
  12.  
  13. data Msg = Msg {_payload :: MsgPayload}
  14.  
  15. data MsgPayload
  16.     = FooMsgPayload' FooMsgPayload
  17.    | BarMsgPayload' BarMsgPayload
  18.     | ZzzMsgPayload' ZzzMsgPayload
  19.  
  20. data FooMsgPayload = FooMsgA String | FooMsgB (Int, Int)
  21. data BarMsgPayload = BarMsgA Double
  22. data ZzzMsgPayload = ZzzMsgA | ZzzMsgB (Char -> Char) | ZzzMsgC
  23.  
  24. class IsMsgPayload a where
  25.    toMsgPayload :: a -> MsgPayload
  26.  
  27. instance IsMsgPayload FooMsgPayload where
  28.    toMsgPayload = FooMsgPayload'
  29. instance IsMsgPayload BarMsgPayload where
  30.     toMsgPayload = BarMsgPayload'
  31. instance IsMsgPayload ZzzMsgPayload where
  32.    toMsgPayload = ZzzMsgPayload'
  33.  
  34. class Monad m => MsgsRead m where
  35.     readMsgPayloads :: IsMsgPayload a => m [a]
  36. class Monad m => MsgsWrite m where
  37.     writeMsgs :: [Msg] -> m ()
  38.  
  39. initMsg :: IsMsgPayload a => a -> Msg
  40. initMsg payload = Msg (toMsgPayload payload)
  41.  
  42.  
  43. newtype AppEnv a = AppEnv (ReaderT () (StateT () IO) a)  -- pretend the () are useful types
  44.     deriving (Functor, Applicative, Monad)
  45.  
  46. instance MsgsRead AppEnv where
  47.     readMsgPayloads = return []  -- implementation omitted
  48. instance MsgsWrite AppEnv where
  49.     writeMsgs _ = return ()      -- implementation omitted
  50.  
  51. runAppEnv :: AppEnv () -> IO ()
  52. runAppEnv (AppEnv appEnv) = evalStateT (runReaderT appEnv ()) ()
  53.  
  54.  
  55. data AllowFooZzzMsgs  -- only allow FooMsgPayload/ZzzMsgPayload messages
  56. data AllowBarMsgs     -- only allow BarMsgPayload messages
  57.  
  58. newtype RMsg r = RMsg Msg  -- r is a phantom type
  59.  
  60. class IsMsgPayload a => RIsMsgPayloadRead r a where
  61. class IsMsgPayload a => RIsMsgPayloadWrite r a where
  62.  
  63. instance RIsMsgPayloadRead AllowBarMsgs BarMsgPayload where
  64. instance RIsMsgPayloadWrite AllowFooZzzMsgs FooMsgPayload where
  65. instance RIsMsgPayloadWrite AllowFooZzzMsgs ZzzMsgPayload where
  66.  
  67. class MsgsRead m => RMsgsRead r m where
  68.     rReadMsgPayloads :: RIsMsgPayloadRead r a => m [a]
  69.     rReadMsgPayloads = readMsgPayloads
  70.  
  71. class MsgsWrite m => RMsgsWrite r m where
  72.     rWriteMsgs :: [RMsg r] -> m ()
  73.     rWriteMsgs msgs = writeMsgs [msg | RMsg msg <- msgs]
  74.  
  75. initRMsg :: RIsMsgPayloadWrite r a => a -> RMsg r
  76. initRMsg payload = RMsg (initMsg payload)
  77.  
  78. -- AppEnv is allowed to read/write any message if no RIsMsgPayloadRead/RIsMsgPayloadWrite constraints are specified
  79. instance RMsgsRead AllowFooZzzMsgs AppEnv
  80. instance RMsgsRead AllowBarMsgs AppEnv
  81. instance RMsgsWrite AllowFooZzzMsgs AppEnv
  82. instance RMsgsWrite AllowBarMsgs AppEnv
  83.  
  84.  
  85. f1 :: forall m. MsgsRead m => m ()
  86. f1 = void (readMsgPayloads :: m [FooMsgPayload])
  87.  
  88. f2 :: MsgsWrite m => m ()
  89. f2 = writeMsgs [initMsg ZzzMsgA]
  90.  
  91. f3 :: forall m. (MsgsRead m, MsgsWrite m) => m ()
  92. f3 = do
  93.     void (readMsgPayloads :: m [BarMsgPayload])
  94.     writeMsgs [initMsg ZzzMsgC]
  95.  
  96. rF1 :: forall m. RMsgsRead AllowBarMsgs m => m ()
  97. rF1 = void (rReadMsgPayloads @AllowBarMsgs :: m [BarMsgPayload])
  98.  
  99. rF2 :: RMsgsWrite AllowFooZzzMsgs m => m ()
  100. rF2 = rWriteMsgs @AllowFooZzzMsgs [initRMsg ZzzMsgA]
  101.  
  102. main :: IO ()
  103. main = do
  104.     runAppEnv $ f1 >> f2 >> f3  -- pretend this is doing something useful
  105.     runAppEnv $ rF1 >> rF2      -- pretend this is doing something useful
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement