[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