我正在编写一个通过网络与远程端通信的Haskell应用程序,并将收到的消息累积到状态monad中的状态对象中:
template <typename T, T ... Numbers>
class Sequence final {
static constexpr bool is_all_zero_or_one(std::initializer_list<T> list) {
for (auto elem : list) {
if (elem != 0 && elem != 1) return false;
}
return true;
}
static_assert(is_all_zero_or_one({Numbers...}),
"Only zeroes and ones are allowed.");
};
我已将状态对象建模为包含许多newtype ProtoS r s a = CProtoS {
getProtoS :: S.StateT s (ReaderT r (ExceptT ProtocolError IO)) a
} deriving (Monad, Functor, Applicative, MonadError ProtocolError, MonadIO)
个对象的数据类型。以下是服务器端的示例:
Maybe *msg*
按照它们在ServerProtocolState类型中出现的顺序接收消息。所以首先状态为空(所有data ServerProtocolState = ServerProtocolState {
spsChannelOpenParameters :: Maybe ClientVersion
,spsOpenResponse :: Maybe OpenResponse
,spsOpenFinalize :: Maybe OpenFinalize
,spsLastPayment :: Maybe Payment
} deriving Show
s),然后接收到ClientVersion,现在状态包含Nothing
,其余的都是Nothing,然后接收下一条消息,状态为{ {1}},等等。
如何在收到对象之前尝试从此状态检索对象,无法代表?或者有更好的方法来模拟它吗?
答案 0 :(得分:1)
您可以创建类型的层次结构,每个类型包含先前级别的信息。所以,例如:
data Level0 = Level0
data Level1 = Level1 Level0 ClientVersion
data Level2 = Level2 Level1 OpenResponse
data Level3 = Level3 Level2 OpenFinalize
data Level4 = Level4 Level3 Payment
然后你可以按照你所处的等级来设置你的monad参数,并且你想要添加一些&#34; promotion&#34;功能。例如:
receiveVersion :: MonadIO m => ReaderT Level1 m a -> ReaderT Level0 m a
receiveVersion action = do
version <- liftIO ({- ... -})
ReaderT $ \level0 -> runReaderT action (Level1 level0 version)
您当然可以执行各种类型级别的hackery和类型类hackery,以使所有提升函数具有相同的名称,并更抽象地指定信息层次结构。