I’d favor (a,a)->a->a now that hvr has pointed it out. (I think that order lends itself to slightly better specialization on partial applipkiation internally )
After sleeping on it, I absolutely agree with david about uniform strictness is the best option. I’ll help sandy reflect both of these things into the final code.
And as lennart mentioned, Clamp is bog standard.
And amusingly enough, the stranger bits of how min and max in the c standards interact with nans and infinities (avoiding rather than poisoning) are due to wanting clamping for rendering plots to be simple to write in c!
On Sat, Aug 15, 2020 at 5:59 AM Herbert Valerio Riedel <
hvr@gnu.org> wrote:
> It seems to me that base is missing the very standard function `clamp ::
> Ord a => a -> a -> a -> a`:
>
> ```haskell
> clamp :: Ord a => a -> a -> a -> a
> clamp low high = min high .max low
> ```
>
> I propose it be added to Data.Ord. It's useful, generic, and non-trivial to
> get right (the "big" number goes with "min" -- causes me cognitive
> dissonance every time.)
I'm -1 on the proposed type-signature.
For one, while the motivation mentions cognitive overhead, it's ironic
that the proposed
:: Ord a => a -> a -> a -> a
with three `a`-typed parameters whose grouping/semantics is all but
obvious if you merely see the type-signature without knowing its
implementation is itself a source of cognitive overhead IMO.
On the other hand, there are already related functions taking
lower/upper bounds defined by the Haskell Report, see
https://www.haskell.org/onlinereport/haskell2010/haskellch19.html#x27-22500019
and so it'd help to kill two birds with one stone by align the proposed
`clamp` with the precedent established by the pre-existing functions in
Data.Ix, such as
,----
| class Ord a => Ix a where
|
| range :: (a, a) -> [a]
| The list of values in the subrange defined by a bounding pair.
|
| index :: (a, a) -> a -> Int
| The position of a subscript in the subrange.
|
| inRange :: (a, a) -> a -> Bool
| Returns True the given subscript lies in the range defined the bounding pair.
|
| rangeSize :: (a, a) -> Int
| The size of the subrange defined by a bounding pair.
`----
So by grouping the type-signature like
clamp :: Ord a => (a,a) -> a -> a
or even
clamp :: Ord a => a -> (a,a) -> a
it becomes a lot more obvious which parameters are the bounds and which
is the subject it's operating upon and it's IMO less error-prone as
there's now less risk to accidentally swap parameters around.
Moreover, this turns `clamp` into a function taking two parameters,
thereby allowing `clamp` to be used as infix operator
(lower,upper) `clamp` x
Having lower/upper bounds represented as tuple also makes it easier to
define constants denoting the bounds, c.f.
| ... = f (clamp int7Bounds x) ...
| where
| int7Bounds = (0,127)
Long story short, I'm -1 on the proposed type-signature; I'm
not against using a type-signature which groups the bounds-parameter
into a tuple in alignment with the "Data.Ix" API.
-- hvr
_______________________________________________
Libraries mailing list
Libraries@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries