> instance ShowType a => ShowType [a]
> where
> showsType xs = ('[':) . showsType x . (']':) where ~(x:_) = xs
>
> Looks like ~(x:_) gives access to a constant instance operation
> on the type of an element of xs even when xs is empty.
>
> Looks like it works. But I do not understand the whole thing, so far.
The assumption is that for all instances of "ShowType", the argument
of the "showsType" function is either:
* not used at all (e.g. for Int, Char, etc.); or
* used only in a recursive call at a less complex type.
Hence, by induction, the argument value is never examined by _any_
runtime call. (And because where/let bindings are lazy, I think
probably you don't even need the ~(x:_) lazy pattern; just (x:_)
would suffice.) However, the compiler must examine the pattern to
determine type information, and thus calculates the correct dictionary
to plug in.
The same trick extends nicely to sum types as well:
instance (ShowType a, ShowType b) => ShowType (Either a b) where
showsType x = showString "Either " .
showsType a . showChar ' '
showsType b
where (Left a) = x
(Right b) = x
Notice how the argument x is pattern-matched twice, at quite different
values!
Regards,
Malcolm