我刚刚开始学习Haskell。据我所知maximum
给出了整数列表的最大值。因此,maximum [2,5,7,1]
给出7。但是为什么通过给出一个元组输入,最大值却总是给出第二个元素?例如,maximum (8,1)
给出1。sum (8,1)
,product (5,2)
,minimum (4,5)
...也会发生相同的情况,所有这些都给出元组的第二个元素。因此,任何人都可以向初学者解释为什么会发生这种情况吗?
简短回答:对于2元组,Foldable
实例(仅)将第二项考虑在内。因此,maximum
函数将始终返回2元组的第二项。
因为2元组是Foldable
的实例。确实是defined as [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)
所以在这里我们用mf
(作为y
参数)和x
作为Nothing
来调用m
。此case … of …
与Nothing
匹配并返回x
。因此,一个2元组的最大值定义为:
maximum (_, y) = fromMaybe (error "…") (Just y)
因此更短:
-- maximum for a (a, b)
maximum (_, y) = y
Haskell中的字符串不是多值容器,就像它们在Python中一样。相反,它们更接近single值的容器,例如Maybe a
或Either b a
:具有上下文的值。 Maybe
和Either
都可能没有值(Either
仅提供比Maybe
更多的关于缺少值的信息)的概念,而元组则携带有关值本身的信息的上下文。
[(8, 1
之类的值)不contain两个值8
和1
。相反,8
是一部分包含1
的容器。
因此,元组是可折叠的,即使这样做看起来很琐碎。将类型(a, b)
的值减小为b
的值仅需返回类型b
的值,而不必担心如何处理类型为b
的其他值,因为存在are n't 任何。
>>> maximum (Just 5)
5
>>> minimum (Just 5)
5
>>> maximum (Right 5)
5
>>> minimum (Right 5)
5
>>> maximum (True, 5)
5
>>> minimum (True, 5)
5
与Maybe
或Either
相比,[[此类函数是带有元组的total]。>>>> 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