Unless there's some issues I'm missing, all of the `liftEq` functions could be replaced by just one:
apply :: (f :~: g) -> (a :~: b) -> (f a :~: g b)
`lower` could be generalized:
inner :: (f a :~: g b) -> (a :~: b)
and this could be added:
outer :: (f a :~: g b) -> (f :~: g)
I like these, and prefer them to the existing liftEqN and lower functions. These mirror more accurately what we have in Core (not that that matters much). I should also note that any similar functions are *very* easy for a user to write, so choosing just the right set of combinators is not critical.
I'd be worried about type inference with partial application and reversed parameters. The values of a and b can only be gleaned from the equality witness, so I would think that delaying that parameter would cause some havoc. Is that not what you've seen?
These names are better than mine.
I like your implementation of Nat much more than mine and would be happy to take your definitions wholesale, with your permission. Of course, I should have looked for such a thing before rewriting it myself! But, with all the extra functionality, it feels too big to just be shoehorned into TypeLits.
Perhaps a better solution is to remove Nat1 from TypeLits and then ask that the data-nat package add type-level conversions to and from the TypeLits Nat. Of course, that introduces some naming confusing (two things named Nat!), but there's nothing so special about Nat1 that it needs to live in base. I just thought it would be convenient.
Thanks for taking a look!
Richard