As everyone knows, you can easily build n-tuples out of 2-tuples.
record Twople (A B : Set) : Set where
constructor _,_
field
fst : A
snd : B
n-ple : List Set -> Set
n-ple = foldr Twople Unit
(Agda syntax, but it'll work in Idris, and can be made to work in Haskell, Scala...)
Likewise, you can build n-ary sum types out of binary sums.
data Either (A B : Set) : Set where
left : A -> Either A B
right : B -> Either A B
OneOf : List Set -> Set
OneOf = foldr Either Void
Simple, and pretty, but inefficient. Plucking the rightmost item from an n-ple
takes O(n) time because you have to unpack every nested Twople
on the way. n-ple
is more like a heterogeneous list than a tuple. Likewise, in the worst case, a OneOf
value lives at the end of n-1
right
s.
The inefficiency can be mitigated by manually unpacking the fields, and inlining the constructor cases, of your datatypes:
record Threeple (A B C : Set) : Set where
constructor _,_,_
field
fst : A
snd : B
thd : C
data Threeither (A B C : Set) : Set where
left : A -> Threeither A B C
middle : B -> Threeither A B C
right : C -> Threeither A B C
Picking an item from a Threeple
and performing case-analysis on a Threeither
are both now O(1). But there's a lot of typing involved, and not the good kind - Fourple
, Nineither
, Hundredple
, and so on, must all be separately defined datatypes.
Must I choose between O(1) time and O(1) lines of code? Or can dependent types help me out? Can one efficiently abstract over datatype arity?