If you like a tool, never look at its headers.

Following hot on the heels of this astonishing header from Boost, here are some excerpts from the module defining tuples in the Glasgow Haskell Compiler 7.4.1:

data (,) a b = (,) a b
    deriving Generic
data (,,) a b c = (,,) a b c
    deriving Generic

(If you can’t read Haskell: (,) a b is another notation for (a, b). This defines types for two- and three-element tuples, with a default implementation of the Generic interface.) Okay so far? The file proceeds to define 4-tuples, 5-tuples, and so on until we get to the 8-tuple definition:

data (,,,,,,,) a b c d e f g h = (,,,,,,,) a b c d e f g h
    -- deriving Generic

Surprise commented-out deriving clause! But it’s all plain sailing from here… until we get to 63-tuples:

data (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__
 = (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__
    -- deriving Generic
{- Manuel says: Including one more declaration gives a segmentation fault.
data (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__ k__
 = (,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,) a b c d e f g h i j k l m n o p q r s t u v w x y z a_ b_ c_ d_ e_ f_ g_ h_ i_ j_ k_ l_ m_ n_ o_ p_ q_ r_ s_ t_ u_ v_ w_ x_ y_ z_ a__ b__ c__ d__ e__ f__ g__ h__ i__ j__ k__

…followed by commented-out definitions of everything up to 100-tuples.

6 comments ↓

#1 Nicolas Trangez on 03.29.12 at 10:38 pm

Would you have any suggestions for another (less ‘verbose’) implementation? This might look somewhat stupid, but it’s the most obvious way as well IMO…

#2 Will Thompson on 03.30.12 at 7:00 am

No—I don’t think there’s anything wrong with writing out 100 tuple definitions longhand. The bits I think are surprising/funny are the inconsistencies shown in the second and third code blocks (and the commented out standalone deriving statements for every tuple type, which I didn’t mention in the post).

#3 Nicolas Trangez on 03.30.12 at 8:55 am

I assumed the removal of Generic deriving for large tuples would be caused by GHC not being able to derive these instances within reasonable space/time constraints.

Looks to be the case indeed:

7fcfc880853fa399c9468049aeb14e6eadb9eae5 Don’t derive Generic for tuples for now

It causes GHC to use vast amounts of space compiling GHC/Tuple.hs.

https://github.com/ghc/packages-ghc-prim/commit/7fcfc880853fa399c9468049aeb14e6eadb9eae5

#4 Ole Laursen on 03.30.12 at 1:19 pm

The works-up-to-n-elements thing reminds me of my college days where I was helping a fellow group of students with a programming assignment for a programming 101 course (with SML). They were all on the math line, not the comp. sci line, and so had chosen an assignment to build a basic library for representing matrices and doing linear algebra. They couldn’t quite figure out how to get the data structure right.

When I gave a (recursive) hint that finally made them realize it was much simpler than they’d thought, one of them said triumphantly: “Hah, but how do you represent an infinite-size matrix with that!”

#5 R on 04.01.12 at 9:50 am

A more expressive notation system (that does not allow to define infix operators) could solve this. In Coq, we can write the following:

Inductive prod (A B:Type) : Type :=
pair : A -> B -> prod A B.
Notation “( x , y , .. , z )” := (pair .. (pair x y) .. z).

#6 R on 04.01.12 at 9:51 am

> that does not allow to define infix operators
that does not ONLY allow to define infix operators