Help with complicated type inference

I'm trying to write an AMQP framing layer. AMQP has two very similar union types: there is a "variant" that contains a single item, and an "array" which consists of a list of elements of the same type. So I thought I could define a "Unit" type container thus:
newtype Unit a = Unit {unUnit :: a}
So now I can say:
type AmqpVariant = AmqpVariantBase Unit type AmqpArray = AmqpVariantBase []
Then the AmqpVariantBase type looks something like this (except that it doesn't work, see below):
data forall a . (AmqpWire a, AmqpWire (c a)) => AmqpVariantBase c = AmqpVarBin8 (c Bin8) | AmqpVarInt8 (c Int8) | AmqpVarUint8 (c Word8) | AmqpVarChar (c Word8) | AmqpVarBoolean (c Bool) | AmqpVarBin16 (c Bin16) | AmqpVarInt16 (c Int16) | AmqpVarUint16 (c Word16) | AmqpVarBin32 (c Bin32) | AmqpVarInt32 (c Int32) -- And on for about 20 more types, including compound types.
All AMQP types have to be seralised, so I've defined a class "AmqpWire" for serialisation in AMQP format. All the individual types (Bin8, Int8 etc) are instances of this class. I've also defined instances for Unit and [] such as:
instance (AmqpWire a) => AmqpWire (Unit a) where amqpPut = amqpPut . unUnit amqpGet = map Unit amqpGet
The problem is with the type constraint for AmqpVariantBase. I need to say "AmqpWire (c a)" without explicitly listing all the values of "a" (i.e. Bin8, Int8, etc) because any time I use AmqpVariantBase I have to repeat the same constraint. How do I do this? Paul.

Hello,
How about defining the types like this:
data PVal a = Unit a | Array [a]
data Val = IntVal (PVal Int) | BoolVal (PVal Bool) -- | etc
instance Serialize Int where ...
instance Serialize a => Serialize (PVal a) where ...
instance Serialize Val where ...
Hope this helps.
-Iavor
On Sun, Apr 27, 2008 at 4:07 AM, Paul Johnson
I'm trying to write an AMQP framing layer. AMQP has two very similar union types: there is a "variant" that contains a single item, and an "array" which consists of a list of elements of the same type. So I thought I could define a "Unit" type container thus:
newtype Unit a = Unit {unUnit :: a}
So now I can say:
type AmqpVariant = AmqpVariantBase Unit type AmqpArray = AmqpVariantBase []
Then the AmqpVariantBase type looks something like this (except that it doesn't work, see below):
data forall a . (AmqpWire a, AmqpWire (c a)) => AmqpVariantBase c = AmqpVarBin8 (c Bin8) | AmqpVarInt8 (c Int8) | AmqpVarUint8 (c Word8) | AmqpVarChar (c Word8) | AmqpVarBoolean (c Bool) | AmqpVarBin16 (c Bin16) | AmqpVarInt16 (c Int16) | AmqpVarUint16 (c Word16) | AmqpVarBin32 (c Bin32) | AmqpVarInt32 (c Int32) -- And on for about 20 more types, including compound types.
All AMQP types have to be seralised, so I've defined a class "AmqpWire" for serialisation in AMQP format. All the individual types (Bin8, Int8 etc) are instances of this class. I've also defined instances for Unit and [] such as:
instance (AmqpWire a) => AmqpWire (Unit a) where amqpPut = amqpPut . unUnit amqpGet = map Unit amqpGet
The problem is with the type constraint for AmqpVariantBase. I need to say "AmqpWire (c a)" without explicitly listing all the values of "a" (i.e. Bin8, Int8, etc) because any time I use AmqpVariantBase I have to repeat the same constraint. How do I do this?
Paul. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Iavor Diatchki wrote:
Hello, How about defining the types like this:
data PVal a = Unit a | Array [a] data Val = IntVal (PVal Int) | BoolVal (PVal Bool) -- | etc
instance Serialize Int where ... instance Serialize a => Serialize (PVal a) where ... instance Serialize Val where ...
Thanks, but its not quite what I'm looking for. It gives an AMQP "array" of Int8 the same type as an AMQP "variant" containing an Int8. I'd prefer them to have distinct types. Paul.

On 4/27/08, Paul Johnson
I'm trying to write an AMQP framing layer. AMQP has two very similar union types: there is a "variant" that contains a single item, and an "array" which consists of a list of elements of the same type. So I thought I could define a "Unit" type container thus:
newtype Unit a = Unit {unUnit :: a}
So now I can say:
type AmqpVariant = AmqpVariantBase Unit type AmqpArray = AmqpVariantBase []
Then the AmqpVariantBase type looks something like this (except that it doesn't work, see below):
data forall a . (AmqpWire a, AmqpWire (c a)) => AmqpVariantBase c = AmqpVarBin8 (c Bin8) | AmqpVarInt8 (c Int8) | AmqpVarUint8 (c Word8) | AmqpVarChar (c Word8) | AmqpVarBoolean (c Bool) | AmqpVarBin16 (c Bin16) | AmqpVarInt16 (c Int16) | AmqpVarUint16 (c Word16) | AmqpVarBin32 (c Bin32) | AmqpVarInt32 (c Int32) -- And on for about 20 more types, including compound types.
All AMQP types have to be seralised, so I've defined a class "AmqpWire" for serialisation in AMQP format. All the individual types (Bin8, Int8 etc) are instances of this class. I've also defined instances for Unit and [] such as:
instance (AmqpWire a) => AmqpWire (Unit a) where amqpPut = amqpPut . unUnit amqpGet = map Unit amqpGet
The problem is with the type constraint for AmqpVariantBase. I need to say "AmqpWire (c a)" without explicitly listing all the values of "a" (i.e. Bin8, Int8, etc) because any time I use AmqpVariantBase I have to repeat the same constraint. How do I do this?
How about class AmqpWireC c where amqpPutC :: AmqpWire a => c a -> ... amqpGetC :: AmqpWire a => ... -> c a instance AmqpWireC Unit where amqpPutC = amqPut . unUnit amqpGetC = Unit . amqpGet instance (AmqpWire a, AmqpWireC c) => AmqpWire (c a) where amqpPut = amqpPutC amqpGet = amqpGetC data (AmqpWireC c) => AmqpVariantBase c = AmqpVarBin8 (c Bin8) | AmqpVarInt8 (c Int8) ... Does that work like you intended? Cheers, /Niklas
participants (3)
-
Iavor Diatchki
-
Niklas Broberg
-
Paul Johnson