0

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

data Thing

width :: Thing -> Double

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

这正确地抱怨了缺少的Bounded实例Double,因为使用的Monoid实例。Max amempty = minBound

我看到源Data.Foldable使用不同的定义newtype Max来实现maximum。该变体会很好,但它似乎没有被导出:

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

1 回答 1

4

您可以使用Optionmonoid 来获取任何Semigroup. Option a只是一个 newtype 包装器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

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

如果您正在使用base-4.11.0或更高版本,则不再需要该Option a类型,因为Monoid (Maybe a)Semigroup a. 因此base-4.11.0,从 GHC 8.4.1 附带的 开始,您可以编写:

maximumMaybe :: (Ord a, Foldable t) => t a -> Maybe a
maximumMaybe = fmap getMax . foldMap (Just . Max)  
于 2018-08-03T15:57:04.617 回答