The type (a,b,c,d)
has a different performance profile from (a,(b,(c,(d,()))))
. In general, indexing into an n-tuple takes O(1)
while indexing into an "hlist" of n nested tuples takes O(n)
.
That said, you should check out Oleg's classic work on HLists. Using HLists requires extensive, and somewhat sketchy, use of type level programming. Many people find this unacceptable, and it was not available in early Haskell. Probably the best way to represent an HList today is with GADTs and DataKinds
data HList ls where
Nil :: HList '[]
Cons :: x -> HList xs -> HList (x ': xs)
This give canonical nesting, and lets you write functions that work for all instances of this type. You could implement your multi way zipWith
using the same techniques as used in printf. A more interesting puzzle is to generate the appropriate lenses for this type (hint: use type level naturals and type families for indexing in).
I have considered writing an HList like library that used arrays and unsafeCoerce
under the hood to get tuple like performance while sticking to a generic interface. I haven't done it, but it should not be overly difficult.
EDIT: the more I think about this the more inclined I am to hack something together when I have the time. The repeated copying problem Andreas Rossberg mentions can probably be eliminated using stream fusion or similar techniques.