Haskell 具有和类型的二进制实例

Haskell 具有和类型的二进制实例,haskell,Haskell,我正在处理两个不同的协议,并将它们的消息存储在一个通道中。为此,我使用了一个sum类型来捕获这两种类型的消息。现在我在为Binary编写解码实例时遇到了困难-我知道要解码哪个协议,但我不知道如何在不使用丑陋的newtype包装器的情况下强制执行它。代码是: -- Supported protocols data ProtoA = ProtoA data ProtoB = ProtoB -- Protocol sum type for storing messag

我正在处理两个不同的协议,并将它们的消息存储在一个通道中。为此,我使用了一个sum类型来捕获这两种类型的消息。现在我在为
Binary
编写解码实例时遇到了困难-我知道要解码哪个协议,但我不知道如何在不使用丑陋的newtype包装器的情况下强制执行它。代码是:

    -- Supported protocols
    data ProtoA = ProtoA
    data ProtoB = ProtoB

    -- Protocol sum type for storing messages in a channel.
    data P = PA ProtoA | PB ProtoB

    -- messages stored in a channel that can support either message.
    type PChan = TChan P

    instance Binary ProtoA where
      put ProtoA = return ()
      get = return ProtoA

    instance Binary ProtoB where
      put ProtoB = return ()
      get = return ProtoB

    instance Binary P where
      -- on put, have the constructor available to drive behavior
      put (PA ProtoA) = return ()
      put (PB ProtoB) = return ()
      -- on get, nothing to differentiate behavior
      -- don't want alternation
      get = undefined

    -- Yuck, wrapped newtypes instances...
    newtype PA' = PA' P
    newtype PB' = PB' P

    instance Binary PA' where
      put (PA' (PA ProtoA)) = return ()
      put (PA' (PB ProtoB)) = fail "shouldn't happen"
      get = return (PA' (PA ProtoA))

    instance Binary PB' where
      put (PB' (PA ProtoA)) = fail "shouldn't happen"
      put (PB' (PB ProtoB)) = return ()
      get = return (PB' (PB ProtoB))

有没有更好的方法来处理这个问题?也许是幻影类型?在解码时,我知道我在处理哪个协议,但不知道如何强制执行。非常欢迎您的建议和/或建议!谢谢

如果您知道您只有
ProtoA
ProtoB
消息,请使用
get::get ProtoA
get::get ProtoB
阅读它们。如果您知道这是一个
ProtoA
,那么没有理由尝试阅读
P
。如果你想要一个
P
持有
ProtoA
,你可以使用
(PA-get)::get P

除非您不知道
p
PA
还是
PB
,否则您不会读取
p
,因此您的
二进制p
实例应该编写一个标记,用于区分
PA
s和
PB
s

instance Binary P where
    put (PA a) = do put (0 :: Word8)
                    put a
    put (PB b) = do put (1 :: Word8)
                    put b
    get = do t <- get :: Get Word8
             case t of
                  0 -> PA <$> get
                  1 -> PB <$> get
实例二进制P,其中
put(PA a)=do put(0::Word8)
放
put(PB b)=do put(1::Word8)
放b
得到
1->PB获取

如果您要将
p
s写入只应为
ProtoA
s或
ProtoB
s的某个位置,那么您的工作就是检查并确保这是真的。然后使用
put::ProtoA->put
put::ProtoB->put
如果您知道只有
ProtoA
ProtoB
消息,请使用
get::get ProtoA
get::get ProtoB
阅读它们。如果您知道这是一个
ProtoA
,那么没有理由尝试阅读
P
。如果你想要一个
P
持有
ProtoA
,你可以使用
(PA-get)::get P

除非您不知道
p
PA
还是
PB
,否则您不会读取
p
,因此您的
二进制p
实例应该编写一个标记,用于区分
PA
s和
PB
s

instance Binary P where
    put (PA a) = do put (0 :: Word8)
                    put a
    put (PB b) = do put (1 :: Word8)
                    put b
    get = do t <- get :: Get Word8
             case t of
                  0 -> PA <$> get
                  1 -> PB <$> get
实例二进制P,其中
put(PA a)=do put(0::Word8)
放
put(PB b)=do put(1::Word8)
放b
得到
1->PB获取
如果您要将
p
s写入只应为
ProtoA
s或
ProtoB
s的某个位置,那么您的工作就是检查并确保这是真的。然后使用
put::ProtoA->put
put::ProtoB->put