序列号的建设性处理
Constructive handling of sequence numbers
我正在实施一个简单的协议,其中消息具有一个序列号,该序列号必须在消息之间严格递增。为了解决这个问题,我写道:
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
具有相同的布尔盲问题。我怎样才能做得更好?
我想到了这个:
data SequenceTag = Initial | Following
newtype SequenceNo (t :: SequenceTag) = SequenceNo Int64
deriving (Show, Eq)
advanceSequence ::
SequenceNo 'Initial ->
SequenceNo 'Following ->
Maybe (SequenceNo 'Initial)
advanceSequence (SequenceNo firstS) (SequenceNo secondS)
| firstS + 1 == secondS = Just (SequenceNo secondS)
| otherwise = Nothing
用法:
applyUpdates :: ProtocolState -> UpdateMessage -> Either String ProtocolState
applyUpdates oldState upd =
case advanceSequence (seqNo oldState) (updSeqNo upd) of
Just s -> Right (ProtocolState {seqNo=s, …})
Nothing -> Left "invalid sequence"
好多了,但还是有点笨拙?
我只想定义一个与 Bool
同构的类型,但具有更具描述性的构造函数名称。
date Validity = Valid | Invalid
然后编写一个函数,returns 种类 由参数表示的序列:
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"
尽管您也可以考虑显式错误类型:
<b>data SequenceError = InvalidSequence</b>
applyUpdates :: ProtocolState -> UpdateMessage -> Either <b>SequenceError</b> ProtocolState
applyUpdates oldState upd =
case validSequence (seqNo oldState) (updSeqNo upd) of
Valid -> Right (ProtocolState {seqNo=updSeqNo upd, …})
Invalid -> Left <b>InvalidSequence</b>
我正在实施一个简单的协议,其中消息具有一个序列号,该序列号必须在消息之间严格递增。为了解决这个问题,我写道:
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
具有相同的布尔盲问题。我怎样才能做得更好?
我想到了这个:
data SequenceTag = Initial | Following
newtype SequenceNo (t :: SequenceTag) = SequenceNo Int64
deriving (Show, Eq)
advanceSequence ::
SequenceNo 'Initial ->
SequenceNo 'Following ->
Maybe (SequenceNo 'Initial)
advanceSequence (SequenceNo firstS) (SequenceNo secondS)
| firstS + 1 == secondS = Just (SequenceNo secondS)
| otherwise = Nothing
用法:
applyUpdates :: ProtocolState -> UpdateMessage -> Either String ProtocolState
applyUpdates oldState upd =
case advanceSequence (seqNo oldState) (updSeqNo upd) of
Just s -> Right (ProtocolState {seqNo=s, …})
Nothing -> Left "invalid sequence"
好多了,但还是有点笨拙?
我只想定义一个与 Bool
同构的类型,但具有更具描述性的构造函数名称。
date Validity = Valid | Invalid
然后编写一个函数,returns 种类 由参数表示的序列:
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"
尽管您也可以考虑显式错误类型:
<b>data SequenceError = InvalidSequence</b>
applyUpdates :: ProtocolState -> UpdateMessage -> Either <b>SequenceError</b> ProtocolState
applyUpdates oldState upd =
case validSequence (seqNo oldState) (updSeqNo upd) of
Valid -> Right (ProtocolState {seqNo=updSeqNo upd, …})
Invalid -> Left <b>InvalidSequence</b>