如何通过foldMap计算可折叠对象的最大浮点数?

时间:2018-08-03 15:18:56

标签: haskell max monoids bounded-types foldable

说我有一个带有可测量对象的地图,我想要它们的最大宽度,默认为0。FoldablefoldMap)和Semigroup({ {3}})看起来很完美,除了我似乎无法引入任意的下限。

data Thing

width :: Thing -> Double

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

这正确地抱怨了Bounded缺少的Double实例,因为Monoid的{​​{1}}实例使用了Max a

我看到mempty = minBound的源使用Max的不同定义来实现newtype Max。该变体效果很好,但似乎无法导出:

Data.Foldable

1 个答案:

答案 0 :(得分:4)

您可以使用Option Monoid获取任何Semigroup的Monoid实例。 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)