2016-05-11 3 views
0

私はいくつかの異なるプロトコルを処理しており、そのメッセージをチャネルに保存しています。これを行うには、両方のタイプのメッセージをキャプチャする合計型を使用しています。 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)) 

これを処理するには良い方法はありますか?おそらくファントムタイプで?デコード時に、私はどのプロトコルを扱っているのか知っていますが、強制する方法はわかりません。アドバイスや提案を大歓迎!ありがとう!

答えて

2

ProtoAまたはProtoBメッセージがあることがわかっている場合は、get :: Get ProtoAまたはget :: Get ProtoBを使用してください。あなたがProtoAであることがわかっている場合は、Pを読むことはできません。 PProtoAの場合は、(PA <$> get) :: Get Pを使用できます。

あなたはそれがPAまたはPBですので、あなたのBinary PインスタンスあなたがPA秒とPBの区別するために使用できるタグを記述する必要があるかどうかわからない場合を除きあなたはPを読むことはありません。

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 

あなたはそれがチェックし、それが真実であることを確認するためにあなたの仕事ですProtoA SまたはProtoB sでなければならないどこかへP秒の書き込みしようとしている場合。次に、put :: ProtoA -> Putまたはput :: ProtoB -> Putを使用します。

関連する問題