说我有一个带有可测量对象的地图,我想要它们的最大宽度,默认为0。Foldable
(foldMap
)和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
答案 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)