
On Wed, Sep 14, 2011 at 9:32 AM, Victor Nazarov
I've just tried another approach (code below). And GHC even inferred type for tupleF. But I think GHC inferred the wrong type and I can't formulate the right one, it seems to require infinite number of constraints. With GHC inferred type this function is not usable, though:
GHC can't actually infer your type with that implementation of tcons. There's no way for it to get from the arguments "THead t" and "TTail t" to the tuple type t, because (unlike type constructors) type families aren't necessarily injective, so there could be more than one type "t" that THead and TTail map to the types received. Furthermore, the open world assumption for type families means that even if there's only one valid "t" in scope, it can't simply select that because it must account for the possibility of more instances being introduced in other scopes. On the other hand, it can get from "t" to "THead t" and "TTail t" just fine, so if you give a type annotation that fixes the result type it should work. But that can be clumsy for actual use. The above issue is exactly why the implementation that I gave uses a slightly peculiar approach to calculate the other types based only on the type of the tuple argument. A slightly more complicated approach could probably be used to get some inference going in both directions, but in most cases the direction I gave will be what you want most. That said, the essential idea of what you're trying to do is a good one. Why not try separating the steps, though? Use one type family to give a bijection between standard tuples and some sort of right-nested pair representation (which is easy to infer both ways), then use standard type-level recursion to process the latter form however you like. You can do generic equivalents of map, fold, zip, &c. this way pretty easily. - C.