It's clear that any n-tuple can be represented by a bunch of nested 2-tuples. So why are they not the same thing in Haskell? Would this break something?
Making these types equivalent would make writing functions on tuples much easier. For example, instead of defining zip,zip2,zip3,etc., you could define only a single zip function that would work for all tuples.
Of course, you can work with nested 2-tuples, but it is ugly and there is no canonical way to perform the nesting (i.e. should we nest to the left or right?).
1. In the monosaccharide derivatives known as sugar alcohols, the carbonyl oxygen is reduced to a hydroxyl group. For example, D-glyceraldehyde can be reduced to glycerol. However, this sugar alcohol is no longer designated D or L.
D-glucose occurs more abundantly in nature than L-glucose. D-glucose is a short form of dextrorotatory glucose. It is one of the two stereoisomers of glucose, and is the one that is biologically active. It occurs in plants as a product of photosynthesis.
Sugar is called by many namesIngredients listed on the food label that end in “ose” are forms of sugar, such as fructose, sucrose, maltose and dextrose. Others can include the following: Brown sugar. Confectioners powdered sugar.
Glucose, fructose and galactose are the three monosaccharides important in nutrition.
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.
The main problem with this in Haskell would be that a nested tuple allows additional values, due to laziness. For example, the type (a,(b,())
is inhabited by all (x,_|_)
or (x,(y,_|_))
, which is not the case for flat tuples. The existence of these values is not only semantically inconvenient, it also would make tuples much more difficult to optimise.
In a strict language, though, your suggestion is indeed a possibility. But it still introduces a performance pitfall: implementations would still want to flatten tuples. Consequently, in the cases where you actually construct or deconstruct them inductively, they would have to do a lot of repeated copying. When you use really large tuples, that might be a problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With