为什么(a,b,c,d)对于(a,(b,(c,(d,()))))不是糖?

很显然,任何n元组都可以用一堆嵌套的2元组来表示。 那么为什么他们在Haskell中不是同一件事呢? 这会打破什么?

使这些types相同将会使元组上的函数写得更容易。 例如,您可以不定义zip,zip2,zip3等,而只定义一个适用于所有元组的zip函数。

当然,你可以使用嵌套的2元组,但它很丑,没有规范的方法来执行嵌套(即我们应该嵌套到左边还是右边?)。

types(a,b,c,d)(a,(b,(c,(d,()))))具有不同的性能分布。 一般来说,索引到一个n元组需要O(1)而索引到n个嵌套元组的“hlist”需要O(n)

也就是说,你应该看看Oleg在HLists上的经典作品。 使用HList需要使用types级别的编程。 许多人认为这是不可接受的,在Haskell早期是不可用的。 今天代表一个HList的最好方法可能是使用GADT和DataKinds

 data HList ls where Nil :: HList '[] Cons :: x -> HList xs -> HList (x ': xs) 

这给了规范的嵌套,并让你编写适用于这种types的所有实例的函数。 您可以使用与printf中使用的相同的技术来实现您的多路zipWith 。 一个更有趣的谜题是为这种types生成适当的镜头(提示:使用types级自然和types家庭进行索引)。

我曾经考虑编写一个像库一样的HList,使用数组和unsafeCoerce来获得类似于性能的元组,同时坚持一个通用的接口。 我没有这样做,但不应该太困难。

编辑:我越想这件事,我就越倾向于在有时间的情况下,共同破解一些东西。 重复的复制问题安德烈亚斯·罗斯伯格提到可能可以使用stream融合或类似的技术来消除。

Haskell中的主要问题是由于懒惰,嵌套元组允许附加值。 例如,types(a,(b,())被所有的(x,_|_)(x,(y,_|_)) ,而不是平面元组的情况。这些值不仅在语义上不方便,而且还会使元组更难以优化。

然而用严格的语言来说,你的build议确实是一种可能性。 但是它仍然引入了一个性能上的问题:实现仍然想要扁平化元组。 因此,在实际构build或解构它们的情况下,他们将不得不做大量的重复复制。 当你使用真正的大元组时,这可能是一个问题。