
Lennart Augustsson
A somewhat similar problem exists even without fields:
foo :: Either a b -> Either () b foo (Left _) = Left () foo x@(Right _) = x
Your example is less surprising than mine with fields. The expression x on the rhs of the last clause has type Either a b This does not match the signature, which claims Either () b So it is fairly easy to explain why this is rejected. Even if we change the definition of the Either type to omit the Left constructor (and correspondingly omit the first clause of foo's definition), you still get an error. Whereas in the named field example, the rhs expression v {field1=Void} does indeed have the type Fields Void as declared in the signature. The expression explicitly converts all the relevant interior fields to Void. At least, that is how it could appear to a naive programmer like me :-) After all, if I change the definition of the type Fields to omit the constructor VariantWithTwo (and correspondingly omit the first clause of voidcast's definition), then suddenly and miraculously, the second clause passes the type checker. It is a bit weird that adding a new constructor to a datatype can cause existing code to fail to typecheck! Regards, Malcolm
data Fields a = VariantWithTwo { field1 :: a , field2 :: a } | VariantWithOne { field1 :: a } data Void = Void
voidcast :: Fields a -> Fields Void voidcast v@(VariantWithTwo{}) = v { field1 = Void , field2 = Void } voidcast v@(VariantWithOne{}) = v { field1 = Void }