I don't know how tuples are internally implemented in GHC, but the Haskell report (3.8) specifically establishes two as their lower size bound.
When provided a zero (or null list) arguments, all TupleT, TupP and TupE behave like the unit type (which is certainly reasonable). However, they handle argument 1 (or the singleton list) in different ways:
- TupleP [pat] is equivalent to pat (which again, is perfectly reasonable)
- TupE [exp] behaves as exp (again, it seems right)
However:
- TupleT 1 `AppT` VarT ''Int is a different type than VarT ''Int
See the following two examples:
- tupE [exp] behaves as expected:
Prelude Language.Haskell.TH> $(sigE (tupE [[|1|]]) (conT ''Int))
1
- tupleT 1 doesn't:
Prelude Language.Haskell.TH> $(sigE [|1|] (tupleT 1 `appT` conT ''Int))
<interactive>:1:2:
No instance for (Num (Int))
arising from the literal `1' at <interactive>:1:2-40
Possible fix: add an instance declaration for (Num (Int))
In the expression: $(sigE [| 1 |] (tupleT 1 `appT` conT 'Int))
In the definition of `it':
it = $(sigE [| 1 |] (tupleT 1 `appT` conT 'Int))
Probably, since unary tuples are not legal, the typechecker should simply raise an error when TupleT is found to have received 1 as argument.