8

我刚刚开始学习 Haskell。据我所知maximum,给出了整数列表的最大值。所以,maximum [2,5,7,1]给出 7。但是为什么通过给出一个元组输入,最大值总是给出第二个元素?例如,maximum (8,1)给出 1。同样的事情发生在sum (8,1), product (5,2), minimum (4,5)... 都给出元组的第二个元素。那么,任何人都可以向初学者解释为什么会发生这种情况吗?

4

2 回答 2

8

简短回答:对于 2 元组,Foldable实例(仅)考虑第二项。因此,该maximum函数将始终返回 2 元组的第二项。

因为 2 元组是Foldable. 实际上,它被定义为 [src]

instance Foldable ((,) a) where
    foldMap f (_, y) = f y

    foldr f z (_, y) = f y z

maximum本质上是一种折叠模式。它等效于:

maximum = foldr1 max

其中foldr1实施为:

foldr1 f = fromMaybe (error "…") . foldr mf Nothing
    where mf x m = Just (case m of
                             Nothing -> x
                             Just y  -> f x y)

所以这意味着对于一个 2 元组,它将被实现为:

maximum (_, y) = fromMaybe (error "…") (mf y Nothing)
    where mf x m = Just (case m of
                             Nothing -> x
                             Just y  -> max x y)

所以这里我们mfy(作为x参数)和Nothingas调用mcase … of …this 匹配并Nothing返回x。因此 2 元组的最大值定义为:

maximum (_, y) = fromMaybe (error "…") (Just y)

因此更短:

-- maximum for a (a, b)
maximum (_, y) = y
于 2019-11-06T10:41:02.350 回答
1

Haskell 中的元组不像 Python 中那样是多值容器。相反,它们更接近于值容器,例如Maybe aor Either b a:带有上下文的值。虽然两者都Maybe带有Either可能没有值的概念(Either只是提供比Maybe缺少值更多的信息),但元组带有关于值本身的信息的上下文。

(8, 1) 这样的值不包含两个值81。相反,8包含1.

因此,元组是可折叠的,即使这样做看起来微不足道。将 type 的值减少为(a, b)的值b只需返回 type 的值b,而不用担心如何处理 type 的其他值b,因为没有任何值。

>>> maximum (Just 5)
5
>>> minimum (Just 5)
5

>>> maximum (Right 5)
5
>>> minimum (Right 5)
5

>>> maximum (True, 5)
5
>>> minimum (True, 5)
5

但是,与or相比,此类函数与元组是完全的:MaybeEither

>>> maximum Nothing
*** Exception: maximum: empty structure
>>> maximum (Left 5)
*** Exception: maximum: empty structure

无论元组包含多少类型,除了最右边的类型之外,所有类型都将固定用于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
于 2019-11-06T16:02:45.717 回答