Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why in Haskell maximum (8,1) = 1? [duplicate]

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?

like image 220
Supriyo Halder Avatar asked Nov 06 '19 10:11

Supriyo Halder


2 Answers

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
like image 158
Willem Van Onsem Avatar answered Sep 24 '22 14:09

Willem Van Onsem


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
like image 23
chepner Avatar answered Sep 23 '22 14:09

chepner