如何通过 foldMap 计算 Foldable 的浮点数 属性 的最大值?

How to compute the maximum of a floating point property of a Foldable via foldMap?

假设我有一个带有可测量对象的地图,我想要它们的最大宽度,默认为 0。Foldable (foldMap) and Semigroup (Max) 的机制看起来很完美,除了我似乎无法引入任意下限。

data Thing

width :: Thing -> Double

maxWidth :: Map k Thing -> Double
maxWidth things = getMax . foldMap (Max . width) $ things

这正确地抱怨 Double 缺少 Bounded 实例,因为 Max aMonoid 实例使用 mempty = minBound.

我看到 Data.Foldable 的来源使用了 newtype Max to implement maximum 的不同定义。该变体会很好,但它似乎无法导出:

maxWidth things = fromMaybe 0 . getMax . foldMap (Max . Just . width) $ things

您可以使用 Option 幺半群来为任何 Semigroup 获取一个幺半群实例。 Option a 只是 Maybe a 的新类型包装器,但它的 Monoid 实例只需要 Semigroup a 而不是 Monoid a。所以我们可以将它与 Max 一起使用:

maximumMaybe :: (Ord a, Foldable t) => t a -> Maybe a
maximumMaybe = fmap getMax . getOption . foldMap (Option . Just . Max)  

如果你想要空列表的默认值,你可以使用fromMaybe:

maximumWithDefault :: (Ord a, Foldable t) => a -> t a -> a 
maximumWithDefault d = fromMaybe d . maximumMaybe

另一种选择是只使用 safe 包中的 maximumMay :: (Ord a, Foldable t) => t a -> Maybe a

如果您使用的是 base-4.11.0 或更高版本,则不再需要 Option a 类型,因为对 Monoid (Maybe a) 的限制已解除为 Semigroup a。因此,从 GHC 8.4.1 附带的 base-4.11.0 开始,您可以这样写:

maximumMaybe :: (Ord a, Foldable t) => t a -> Maybe a
maximumMaybe = fmap getMax . foldMap (Just . Max)