Traversible Functor Data, or: X marks the spot (Re: Haddock version during build)

Claus Reinke claus.reinke at talk21.com
Tue Jun 24 12:03:55 EDT 2008


>    fmap' :: (Data (f X)) => (a -> b) -> f a -> f b
>    fmap' f x = markTheSpots (rec (wrap f)) x
>      where
>      markTheSpots :: (f X -> f X) -> (f a -> f b)
>      markTheSpots f = unsafeCoerce . f . unsafeCoerce
>      rec ::  (Data a) => (X -> X) -> a -> a
>      rec f x = (gmapT (rec f) `extT` f) x
>      wrap :: (a -> b) -> (X -> X)
>      wrap f = unsafeCoerce . f . unsafeCoerce
.. 
> 1. We wrap the function parameter f, to make it look
>    like a type-preserving function, on some private type X.
> 
> 2. We mark the occurrences of the type constructor f's 
>    parameter type, by coercing 'f a' to 'f X' and 'f X' to
>    'f b'.
> 
> Then, we simply use SYB to apply f, when its type matches
> the parameter, or to recurse into the subexpressions using
> gmapT, otherwise. If X is private, f will only be applied
> to the "functor parameter" _positions_ in 'f a', not to other
> "functor parameter" _type_ occurrences in 'f a'

..but f might not be applied at all, which leads to the first
issue with this technique:

I was surprised to see Data instances for (a->b) and IO a, 
since for such non-algebraic types, there isn't anything to 
gfoldl or gmap over. And those instances do indeed seem
to offer very little functionality (not to mention the runtime
errors..). 

For fmap'/traverse', this means that f will not be applied, 
and so it is not a good idea to coerce the types as if f had 
been applied (because the hidden parameter could be 
exposed after traversal, with changed type and unchanged
representation!).. So we need to restrict the types of 
fmap'/traverse'. Which leads to two questions:

- what is the rationale for having these non-functional
    Data instances?

    If one is to have 'instance Data (a->b)', is there a way
    to make it more functional?

- how can we capture algebraic types in a type (class)?

    I thought that Data would do just that, being designed
    to gfoldl over concrete data constructors, but apparently
    not. And I don't really want to have a separate list of 
    all the types for which Data works, or of all the types 
    for which Data doesn't quite work.

Claus

ps. What is the right list for this topic?



More information about the Cvs-libraries mailing list