This is my solution to exercise from YAHT:
Exercise 4.6 Write a datatype Tuple which can hold one, two, three or
four elements, depending on the constructor (that is, there should be
four constructors, one for each number of arguments). Also provide
functions tuple1 through tuple4 which take a tuple and return Just the
value in that position, or Nothing if the number is in valid (i.e.,
you ask for the tuple4 on a tuple holding only two elements).
When I wrote a first line I was excited about simplicity comparing to C#
data Tuplex a b c d = Tuple1 a | Tuple2 a b | Tuple3 a b c | Tuple4 a b c d
-- class Tuplex<a,b,c,d> {
-- Tuplex(a p1){ _p1 = p1; }
-- Tuplex(a p1, b p2){ _p1 = p1; _p2 = p2; }
-- Tuplex(a p1, b p2, c p3){ _p1 = p1; _p2 = p2; _p3 = p3; }
-- Tuplex(a p1, b p2, c p3, d p4){ _p1 = p1; _p2 = p2; _p3 = p3; _p4 = p4; }
-- public Nullable<a> _p1;
-- public Nullable<b> _p2;
-- public Nullable<c> _p3;
-- public Nullable<d> _p4;
-- }
In C# I can access any field without problem, but here I should write an ‘accessor functions’, right? And amount of code here makes me sad.
Can I have shorter code here?
tuple1 ∷ Tuplex a b c d → Maybe a
tuple2 ∷ Tuplex a b c d → Maybe b
tuple3 ∷ Tuplex a b c d → Maybe c
tuple4 ∷ Tuplex a b c d → Maybe d
tuple1 (Tuple1 a) = Just a
tuple1 (Tuple2 a b) = Just a
tuple1 (Tuple3 a b c) = Just a
tuple1 (Tuple4 a b c d) = Just a
tuple2 (Tuple1 a) = Nothing
tuple2 (Tuple2 a b) = Just b
tuple2 (Tuple3 a b c) = Just b
tuple2 (Tuple4 a b c d) = Just b
tuple3 (Tuple1 a) = Nothing
tuple3 (Tuple2 a b) = Nothing
tuple3 (Tuple3 a b c) = Just c
tuple3 (Tuple4 a b c d) = Just c
tuple4 (Tuple1 a) = Nothing
tuple4 (Tuple2 a b) = Nothing
tuple4 (Tuple3 a b c) = Nothing
tuple4 (Tuple4 a b c d) = Just d
-- unit tests
prop_tx1 = tuple1 (Tuple1 4) ≡ Just 4
prop_tx2 = tuple1 (Tuple2 4 'q') ≡ Just 4
prop_tx3 = tuple2 (Tuple1 4) ≡ (Nothing ∷ Maybe Char)
prop_tx4 = tuple2 (Tuple2 4 'q') ≡ Just 'q'
I would try to keep it dead simple: