-primitive arrays. You might think this odd: doesn't being
-heap-allocated mean that it has a box? No, it does not. A primitive
-array is heap-allocated because it is too big a value to fit in a
-register, and would be too expensive to copy around; in a sense, it is
-accidental that it is represented by a pointer. If a pointer
-represents a primitive value, then it really does point to that value:
-no unevaluated thunks, no indirections...nothing can be at the other
-end of the pointer than the primitive value.
-
-This section also describes a few non-primitive types, which are needed
-to express the result types of some primitive operations.
+primitive arrays. A primitive array is heap-allocated because it is
+too big a value to fit in a register, and would be too expensive to
+copy around; in a sense, it is accidental that it is represented by a
+pointer. If a pointer represents a primitive value, then it really
+does point to that value: no unevaluated thunks, no
+indirections...nothing can be at the other end of the pointer than the
+primitive value.
+
+<sect2>Unboxed Tuples
+<label id="unboxed-tuples">
+<p>
+
+Unboxed tuples aren't really exported by @PrelGHC@, they're available
+by default with @-fglasgow-exts@. An unboxed tuple looks like this:
+
+<tscreen><verb>
+(# e_1, ..., e_n #)
+</verb></tscreen>
+
+where @e_1..e_n@ are expressions of any type (primitive or
+non-primitive). The type of an unboxed tuple looks the same.
+
+Unboxed tuples are used for functions that need to return multiple
+values, but they avoid the heap allocation normally associated with
+using fully-fledged tuples. When an unboxed tuple is returned, the
+components are put directly into registers or on the stack; the
+unboxed tuple itself does not have a composite representation. Many
+of the primitive operations listed in this section return unboxed
+tuples.
+
+There are some pretty stringent restrictions on the use of unboxed tuples:
+
+<itemize>
+
+<item> Unboxed tuple types are subject to the same restrictions as
+other unboxed types; i.e. they may not be stored in polymorphic data
+structures or passed to polymorphic functions.
+
+<item> Unboxed tuples may only be constructed as the direct result of
+a function, and may only be deconstructed with a @case@ expression.
+eg. the following are valid:
+
+<tscreen><verb>
+f x y = (# x+1, y-1 #)
+g x = case f x x of { (# a, b #) -> a + b }
+</verb></tscreen>
+
+but the following are invalid:
+
+<tscreen><verb>
+f x y = g (# x, y #)
+g (# x, y #) = x + y
+</verb></tscreen>
+
+<item> No variable can have an unboxed tuple type. This is illegal:
+
+<tscreen><verb>
+f :: (# Int, Int #) -> (# Int, Int #)
+f x = x
+</verb></tscreen>
+
+because @x@ has an unboxed tuple type.
+
+</itemize>
+
+Note: we may relax some of these restrictions in the future.
+
+The @IO@ and @ST@ monads use unboxed tuples to avoid unnecessary
+allocation during sequences of operations.