I have just started learning Haskell. As I know maximum
gives the max value for a list of integers. So, maximum [2,5,7,1]
gives 7. But why by giving a tuple input does maximum always give the second element? E.g., maximum (8,1)
gives 1. The same thing happens with sum (8,1)
, product (5,2)
, minimum (4,5)
... all give the second element of the tuple. So, can anyone explain to a beginner why this happens?
Short answer: for a 2-tuple, the Foldable
instance takes (only) the second item into account. The maximum
function will thus always return the second item of the 2-tuple.
Because a 2-tuple is an instance of Foldable
. Indeed, it is defined as [src]:
instance Foldable ((,) a) where foldMap f (_, y) = f y foldr f z (_, y) = f y z
The maximum
is in essence a foldr pattern. It is implemented as an equivalent of:
maximum = foldr1 max
Where foldr1
is implemented as:
foldr1 f = fromMaybe (error "…") . foldr mf Nothing
where mf x m = Just (case m of
Nothing -> x
Just y -> f x y)
So that means that for a 2-tuple, it will be implemented as:
maximum (_, y) = fromMaybe (error "…") (mf y Nothing)
where mf x m = Just (case m of
Nothing -> x
Just y -> max x y)
So here we call mf
with y
(as x
parameter), and Nothing
as m
. The case … of …
this matches with Nothing
and returns x
. So the maximum for a 2-tuple is defined as:
maximum (_, y) = fromMaybe (error "…") (Just y)
and thus shorter:
-- maximum for a (a, b)
maximum (_, y) = y
Tuples in Haskell are not multi-valued containers like they are in, say, Python. Rather, they are closer to single-valued containers like Maybe a
or Either b a
: a value with a context. While both Maybe
and Either
carry the concept of possibly no value (Either
simply providing more information than Maybe
about the lack of a value), a tuple carries the context of information about the value itself.
A value like (8, 1
) does not contain two values 8
and 1
. Rather, 8
is part of a container that contains a 1
.
As such, tuples are foldable, even if doing so seems trivial. Reducing a value of type (a, b)
to a value of b
simply has to return the value of type b
, without worrying about what to do with the other values of type b
, because there aren't any.
>>> maximum (Just 5)
5
>>> minimum (Just 5)
5
>>> maximum (Right 5)
5
>>> minimum (Right 5)
5
>>> maximum (True, 5)
5
>>> minimum (True, 5)
5
Such functions are total with tuples, though, as compared to Maybe
or Either
:
>>> maximum Nothing
*** Exception: maximum: empty structure
>>> maximum (Left 5)
*** Exception: maximum: empty structure
No matter how many types the tuple contains, all but the right-most one will fixed for any given instance of Foldable
.
-- Actual instance for (a, b)
instance Foldable ((,) a) where
foldMap f (_, y) = f y
foldr f z (_, y) = f y z
-- Instance for (a, b, c) if you wanted it
instance Foldable ((,,) a b) where
foldMap f (_, _, y) = f y
foldr f z (_, _, y) = f y z
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With