Haskell:如何尝试从状态不可代表的方式检索尚未收到的消息?

时间:2016-04-29 09:01:16

标签: haskell types state

我正在编写一个通过网络与远程端通信的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}},等等。

如何在收到对象之前尝试从此状态检索对象,无法代表?或者有更好的方法来模拟它吗?

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,以使所有提升函数具有相同的名称,并更抽象地指定信息层次结构。