Min & Max without Bounded

Oleg Grenrus oleg.grenrus at iki.fi
Wed Nov 11 08:37:13 UTC 2020


In lattices [1] package there is an Ordered newtype with a Lattice
instance where (/\) = min and (\/) = max. Then one can add extra
elements with Lifted (extra bottom), Dropped (extra top) or Levitated
(extra top and bottom). Finally one can convert a Lattice into Monoid
with Meet or Join newtypes.

This is to point out that there are various ways to think about this
issue. I don't think we have found /the/ solution to be in "base".

[1] https://hackage.haskell.org/package/lattices

On 11.11.2020 0.57, Jon Purdy wrote:
>
> On Tue, Nov 10, 2020 at 1:33 PM Hécate <hecate at glitchbra.in
> <mailto:hecate at glitchbra.in>> wrote:
>
>     I invite you to read the source of this module, which may provide
>     some context for the current situation:
>
>     https://hackage.haskell.org/package/base-4.14.0.0/docs/src/Data.Functor.Utils.html#%23
>
>
> Thanks! That is useful context. I was aware that this had been
> considered as a possibility, but having coincidentally run into it
> multiple times recently, I figured I’d propose it in earnest. Since
> there are two reasonable ways to define these, I would prefer to have
> both available. There’s an analogous situation, albeit not for the
> same reasons afaik, with ‘First’ and ‘Last’ from ‘Data.Semigroup’
> (without ‘Maybe’) and ‘Data.Monoid’ (with ‘Maybe’). I wonder if that’s
> considered a good example to follow (i.e. adding
> ‘Data.Monoid.{Max,Min}’) or more an unfortunate side effect of how
> ‘semigroups’ was integrated into ‘base’.
>
> On Tue, Nov 10, 2020 at 1:58 PM Oleg Grenrus <oleg.grenrus at iki.fi
> <mailto:oleg.grenrus at iki.fi>> wrote:
>
>     Aren't Min and Max sufficient by themselves:
>
>     >>> foldMap (Just . Min &&& Just . Max) [1..10 :: Integer]
>     (Just (Min {getMin = 1}),Just (Max {getMax = 10}))
>
>
> That’s a good point, and also a suitable alternative, thank you. I
> guess the main question is whether anyone thinks it important enough
> to add a separate type to provide different instances than this, for
> example ‘Ord’ as I mentioned. If not, I’m satisfied to use this or my
> own definitions.
>
> (More likely the latter, if anyone’s curious, since I also have
> parallel types for lower & upper bounds, where ‘Nothing’ is a zero
> rather than a unit.)
>
>
> On Tue, Nov 10, 2020 at 1:19 PM Jon Purdy <evincarofautumn at gmail.com
> <mailto:evincarofautumn at gmail.com>> wrote:
>
>     The ‘Min’ and ‘Max’ newtypes from ‘Data.Semigroup’ require a
>     ‘Bounded’ constraint for their ‘Monoid’ instances, because they
>     wrap a value of type ‘a’ rather than ‘Maybe a’. The latter is
>     something I’ve needed a few times lately for types that cannot be
>     bounded (or just don’t want to be), and it seems base-worthy to me.
>
>     So if it hasn’t been proposed and dismissed already (or if it has
>     been proposed, but just got backburnered), I’d like to suggest
>     adding the following new types, and at least the following
>     instances, to either ‘Data.Semigroup’ or ‘Data.Monoid’:
>
>     newtype Minimum a = Minimum { getMinimum :: Maybe a }
>       deriving (Eq, Ord, Monoid, Semigroup)
>         via (Down (Maybe (Down (Max a))))
>
>     newtype Maximum a = Maximum { getMaximum :: Maybe a }
>       deriving (Eq, Ord, Monoid, Semigroup)
>         via (Maybe (Max a))
>
>     These instances could be specified explicitly instead of with
>     ‘DerivingVia’, but the essential notion here is that ‘Maximum’
>     uses its empty value ‘Nothing’ as a “negative infinity”, less than
>     all other ‘Just’ values, while ‘Minimum’ reverses that to use
>     ‘Nothing’ as the corresponding “positive infinity”.
>
>     I assume these would also want more or less the same array of
>     instances as for the existing ‘Min’ and ‘Max’, and there is the
>     usual opportunity to bikeshed about the naming and how these
>     instances ought to relate to one another. I figure that at least
>     the ‘Ord’ instance should match the ordering that the ‘Semigroup’
>     instance uses, to avoid some potential for confusion/bugs.
>
>     As for use cases, I tend to reach for these things either in
>     configuration records with many fields that I’m combining by
>     semigroup append (Max, Any, set union, and so on) or when I have a
>     possibly-empty container and don’t want to write e.g. ‘maximum (0
>     : xs)’ to avoid partiality. For example, ‘foldMap (Minimum . Just
>     &&& Maximum . Just)’ computes the minimum and maximum in a single
>     pass, returning Nothing for a null input.
>
>     Any thoughts, critiques, questions, rebuttals, edge cases, use
>     cases, &c. are most welcome!
>
>
> _______________________________________________
> Libraries mailing list
> Libraries at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/libraries/attachments/20201111/0a93b537/attachment-0001.html>


More information about the Libraries mailing list