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:

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