clamp function in base

Herbert Valerio Riedel hvr at gnu.org
Sat Aug 15 09:57:43 UTC 2020


> 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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 227 bytes
Desc: not available
URL: <http://mail.haskell.org/pipermail/libraries/attachments/20200815/2dca7584/attachment.sig>


More information about the Libraries mailing list