[Haskell-cafe] Help with complicated type inference
Niklas Broberg
niklas.broberg at gmail.com
Sun Apr 27 13:20:30 EDT 2008
On 4/27/08, Paul Johnson <paul at cogito.org.uk> wrote:
> 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
More information about the Haskell-Cafe
mailing list