首页 > 解决方案 > 序列号的建设性处理

问题描述

我正在实现一个简单的协议,其中消息的序列号必须在消息之间严格递增。为了解决这个问题,我写道:

newtype SequenceNo = SequenceNo Int64
  deriving (Show, Eq)

validSequence :: SequenceNo -> SequenceNo -> Bool
validSequence (SequenceNo firstS) (SequenceNo secondS) = firstS + 1 == secondS

我使用它是这样的:

applyUpdates :: ProtocolState -> UpdateMessage -> Either String ProtocolState
applyUpdates oldState upd =
  if validSequence (seqNo oldState) (updSeqNo upd)
    then Right (ProtocolState {seqNo=updSeqNo upd, …})
    else Left "invalid sequence"

但这具有与布尔盲相同的问题isJust :: Maybe a -> Bool。我怎样才能做得更好?

标签: haskellnewtype

解决方案


我只想定义一个与 同构的类型Bool,但使用更具描述性的构造函数名称。

date Validity = Valid | Invalid

然后编写一个函数,返回由参数表示的序列类型:

classifySequence :: SequenceNo -> SequenceNo -> Validity
classifySequence (SequenceNo x) (SequenceNo y) | x + 1 == y = Valid
                                               | otherwise = Invalid

如果您Enum为您的类型定义一个实例,那就更简单了。

newtype SequenceNo = SequenceNo Int64 deriving (Show, Read, Eq, Enum)

classifySequence :: SequenceNo -> SequenceNo -> Validity
classifySequence x y | succ x == y = Valid
                     | otherwise = Invalid

无论哪种方式,您都可以定义

applyUpdates :: ProtocolState -> UpdateMessage -> Either String ProtocolState
applyUpdates oldState upd =
  case validSequence (seqNo oldState) (updSeqNo upd) of
    Valid -> Right (ProtocolState {seqNo=updSeqNo upd, …})
    Invalid -> Left "invalid sequence"

尽管您也可能会考虑显式错误类型:

data SequenceError = InvalidSequence

applyUpdates :: ProtocolState -> UpdateMessage -> Either SequenceError ProtocolState
applyUpdates oldState upd =
  case validSequence (seqNo oldState) (updSeqNo upd) of
    Valid -> Right (ProtocolState {seqNo=updSeqNo upd, …})
    Invalid -> Left InvalidSequence

推荐阅读