clamp function in base

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
21 messages Options
12
Reply | Threaded
Open this post in threaded view
|

clamp function in base

Sandy Maguire
Hi all,

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.)

Thanks,
Sandy

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Carter Schonwald


hey sandy!
i absolutely support this, 

theres one gotcha to this definition, handling nans!  I also think that this is version of the definition you propose may benefit from being written less point free (eg   =  \ val -> min high $ max low a) for clarity and for how ghc optimizes

theres several ways we could make it play nice with nans, but maybe this should go in as is, to force me to get irate about ord for floats and finish some long overdue patches to Ord on Float and double :)

either way, please throw a PR onto gitlab and @ myself and other folks for review 



On Fri, Aug 14, 2020 at 5:38 PM Sandy Maguire <[hidden email]> wrote:
Hi all,

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.)

Thanks,
Sandy
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Sandy Maguire

On Fri, Aug 14, 2020 at 5:45 PM Carter Schonwald <[hidden email]> wrote:


hey sandy!
i absolutely support this, 

theres one gotcha to this definition, handling nans!  I also think that this is version of the definition you propose may benefit from being written less point free (eg   =  \ val -> min high $ max low a) for clarity and for how ghc optimizes

theres several ways we could make it play nice with nans, but maybe this should go in as is, to force me to get irate about ord for floats and finish some long overdue patches to Ord on Float and double :)

either way, please throw a PR onto gitlab and @ myself and other folks for review 



On Fri, Aug 14, 2020 at 5:38 PM Sandy Maguire <[hidden email]> wrote:
Hi all,

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.)

Thanks,
Sandy
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Carter Schonwald
Wonderful! Your aside about inverted Lo and hi clamping arguments does raise a fun question about strictness for the value argument!  When  low and hi are equal, the result is constant. Should the value arg be strict or lazy when it’s essentially the constant function? 

On Fri, Aug 14, 2020 at 11:30 PM Sandy Maguire <[hidden email]> wrote:

On Fri, Aug 14, 2020 at 5:45 PM Carter Schonwald <[hidden email]> wrote:


hey sandy!
i absolutely support this, 

theres one gotcha to this definition, handling nans!  I also think that this is version of the definition you propose may benefit from being written less point free (eg   =  \ val -> min high $ max low a) for clarity and for how ghc optimizes

theres several ways we could make it play nice with nans, but maybe this should go in as is, to force me to get irate about ord for floats and finish some long overdue patches to Ord on Float and double :)

either way, please throw a PR onto gitlab and @ myself and other folks for review 



On Fri, Aug 14, 2020 at 5:38 PM Sandy Maguire <[hidden email]> wrote:
Hi all,

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.)

Thanks,
Sandy
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

David Feuer
Strict. Making the function lazy to be extra efficient when given
useless arguments means demand analysis will be worse for no good
reason.

On Fri, Aug 14, 2020 at 11:56 PM Carter Schonwald
<[hidden email]> wrote:

>
> Wonderful! Your aside about inverted Lo and hi clamping arguments does raise a fun question about strictness for the value argument!  When  low and hi are equal, the result is constant. Should the value arg be strict or lazy when it’s essentially the constant function?
>
> On Fri, Aug 14, 2020 at 11:30 PM Sandy Maguire <[hidden email]> wrote:
>>
>> Yay! I've opened !3876 at https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3876
>>
>> On Fri, Aug 14, 2020 at 5:45 PM Carter Schonwald <[hidden email]> wrote:
>>>
>>>
>>>
>>> hey sandy!
>>> i absolutely support this,
>>>
>>> theres one gotcha to this definition, handling nans!  I also think that this is version of the definition you propose may benefit from being written less point free (eg   =  \ val -> min high $ max low a) for clarity and for how ghc optimizes
>>>
>>> theres several ways we could make it play nice with nans, but maybe this should go in as is, to force me to get irate about ord for floats and finish some long overdue patches to Ord on Float and double :)
>>>
>>> either way, please throw a PR onto gitlab and @ myself and other folks for review
>>>
>>>
>>>
>>> On Fri, Aug 14, 2020 at 5:38 PM Sandy Maguire <[hidden email]> wrote:
>>>>
>>>> Hi all,
>>>>
>>>> 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.)
>>>>
>>>> Thanks,
>>>> Sandy
>>>> _______________________________________________
>>>> Libraries mailing list
>>>> [hidden email]
>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
>
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Ivan Lazar Miljenovic
At the risk of bikeshedding, I don't think "clamp" is a very descriptive/findable name for this.  What about "bounded"?

Otherwise, +1

On Sat, 15 Aug 2020 at 13:40, David Feuer <[hidden email]> wrote:
Strict. Making the function lazy to be extra efficient when given
useless arguments means demand analysis will be worse for no good
reason.

On Fri, Aug 14, 2020 at 11:56 PM Carter Schonwald
<[hidden email]> wrote:
>
> Wonderful! Your aside about inverted Lo and hi clamping arguments does raise a fun question about strictness for the value argument!  When  low and hi are equal, the result is constant. Should the value arg be strict or lazy when it’s essentially the constant function?
>
> On Fri, Aug 14, 2020 at 11:30 PM Sandy Maguire <[hidden email]> wrote:
>>
>> Yay! I've opened !3876 at https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3876
>>
>> On Fri, Aug 14, 2020 at 5:45 PM Carter Schonwald <[hidden email]> wrote:
>>>
>>>
>>>
>>> hey sandy!
>>> i absolutely support this,
>>>
>>> theres one gotcha to this definition, handling nans!  I also think that this is version of the definition you propose may benefit from being written less point free (eg   =  \ val -> min high $ max low a) for clarity and for how ghc optimizes
>>>
>>> theres several ways we could make it play nice with nans, but maybe this should go in as is, to force me to get irate about ord for floats and finish some long overdue patches to Ord on Float and double :)
>>>
>>> either way, please throw a PR onto gitlab and @ myself and other folks for review
>>>
>>>
>>>
>>> On Fri, Aug 14, 2020 at 5:38 PM Sandy Maguire <[hidden email]> wrote:
>>>>
>>>> Hi all,
>>>>
>>>> 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.)
>>>>
>>>> Thanks,
>>>> Sandy
>>>> _______________________________________________
>>>> Libraries mailing list
>>>> [hidden email]
>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
>
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries


--

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Lennart Augustsson
I would pick the name clamp, it is quite common.  And I have often wished for this to be in base. 

On Sat, Aug 15, 2020, 02:24 Ivan Lazar Miljenovic <[hidden email]> wrote:
At the risk of bikeshedding, I don't think "clamp" is a very descriptive/findable name for this.  What about "bounded"?

Otherwise, +1

On Sat, 15 Aug 2020 at 13:40, David Feuer <[hidden email]> wrote:
Strict. Making the function lazy to be extra efficient when given
useless arguments means demand analysis will be worse for no good
reason.

On Fri, Aug 14, 2020 at 11:56 PM Carter Schonwald
<[hidden email]> wrote:
>
> Wonderful! Your aside about inverted Lo and hi clamping arguments does raise a fun question about strictness for the value argument!  When  low and hi are equal, the result is constant. Should the value arg be strict or lazy when it’s essentially the constant function?
>
> On Fri, Aug 14, 2020 at 11:30 PM Sandy Maguire <[hidden email]> wrote:
>>
>> Yay! I've opened !3876 at https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3876
>>
>> On Fri, Aug 14, 2020 at 5:45 PM Carter Schonwald <[hidden email]> wrote:
>>>
>>>
>>>
>>> hey sandy!
>>> i absolutely support this,
>>>
>>> theres one gotcha to this definition, handling nans!  I also think that this is version of the definition you propose may benefit from being written less point free (eg   =  \ val -> min high $ max low a) for clarity and for how ghc optimizes
>>>
>>> theres several ways we could make it play nice with nans, but maybe this should go in as is, to force me to get irate about ord for floats and finish some long overdue patches to Ord on Float and double :)
>>>
>>> either way, please throw a PR onto gitlab and @ myself and other folks for review
>>>
>>>
>>>
>>> On Fri, Aug 14, 2020 at 5:38 PM Sandy Maguire <[hidden email]> wrote:
>>>>
>>>> Hi all,
>>>>
>>>> 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.)
>>>>
>>>> Thanks,
>>>> Sandy
>>>> _______________________________________________
>>>> Libraries mailing list
>>>> [hidden email]
>>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
>
> _______________________________________________
> Libraries mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries


--
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Sven Panne-2
Am Sa., 15. Aug. 2020 um 11:28 Uhr schrieb Lennart Augustsson <[hidden email]>:
I would pick the name clamp, it is quite common.

I would go even further, it is *the* canonical name I would google first, see e.g.

 
No need for creative bikeshedding here when there is already a standard name.

  And I have often wished for this to be in base. 

+1

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Herbert Valerio Riedel
In reply to this post by Sandy Maguire

> 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
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

signature.asc (233 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Carter Schonwald
I like this tuple for the range syntax. Definitely nicer. 

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 <[hidden email]> 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
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Brent Yorgey
+1 for adding clamp :: Ord a => (a,a) -> a -> a.

On Sat, Aug 15, 2020, 8:14 AM Carter Schonwald <[hidden email]> wrote:
I like this tuple for the range syntax. Definitely nicer. 

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 <[hidden email]> 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
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Emily Pillmore
In reply to this post by Sandy Maguire
+1, though, David has good points about unnecessary laziness. I'm fine with the name and the signature 

```
clamp :: Ord a ⇒ (a,a) → a → a
```

(or some variation on the theme). 


On Fri, Aug 14, 2020 at 5:38 PM, Sandy Maguire <[hidden email]> wrote:
Hi all,

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.)

Thanks,
Sandy

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries



_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Sandy Maguire
Sounds good. For whatever reason the tupled arguments make me feel better about the `high<low` having undefined behavior. I'll make the change on the MR.

On Sat, Aug 15, 2020 at 8:22 AM Emily Pillmore <[hidden email]> wrote:
+1, though, David has good points about unnecessary laziness. I'm fine with the name and the signature 

```
clamp :: Ord a ⇒ (a,a) → a → a
```

(or some variation on the theme). 


On Fri, Aug 14, 2020 at 5:38 PM, Sandy Maguire <[hidden email]> wrote:
Hi all,

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.)

Thanks,
Sandy

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries



_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Henning Thielemann
In reply to this post by Sandy Maguire

On Fri, 14 Aug 2020, Sandy Maguire 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
> ```


https://hackage.haskell.org/package/utility-ht-0.0.15/docs/Data-Ord-HT.html#v:limit
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Jon Purdy
I’m also strongly for ‘clamp :: (Ord a) => (a, a) -> a -> a’.

Even if we don’t resolve it now, I do want to mention that, in discussing this with some acquaintances recently, we agreed that one-sided clamps likely warrant a home in ‘Data.Ord’ as well:

atLeast :: (Ord a) => a -> a -> a
atLeast = max
{-# INLINE atLeast #-}

atMost :: (Ord a) => a -> a -> a
atMost = min
{-# INLINE atMost #-}

clamp :: (Ord a) => (a, a) -> a -> a
clamp (lower, upper) = atLeast lower . atMost upper

While their implementations are identical to ‘max’ and ‘min’, semantically they privilege their arguments differently, serving as documentation of intent in code like ‘nonnegative = fmap (atLeast 0)’. The hope is that this may help reduce bugs caused by the common error of mixing up ‘min’ and ‘max’, owing to the unfortunate false friendship between “at least/most” and “the least/most”.


On Sun, Aug 16, 2020 at 2:43 AM Henning Thielemann <[hidden email]> wrote:

On Fri, 14 Aug 2020, Sandy Maguire 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
> ```


https://hackage.haskell.org/package/utility-ht-0.0.15/docs/Data-Ord-HT.html#v:limit
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Carter Schonwald
actually, if you look at the associated ticket, we have a version of clamp that gives the right way to derive the onesided behaviors for even floating point! (and has the correct / desirable behavior in the presence of NANs! )

On Wed, Aug 26, 2020 at 8:38 PM Jon Purdy <[hidden email]> wrote:
I’m also strongly for ‘clamp :: (Ord a) => (a, a) -> a -> a’.

Even if we don’t resolve it now, I do want to mention that, in discussing this with some acquaintances recently, we agreed that one-sided clamps likely warrant a home in ‘Data.Ord’ as well:

atLeast :: (Ord a) => a -> a -> a
atLeast = max
{-# INLINE atLeast #-}

atMost :: (Ord a) => a -> a -> a
atMost = min
{-# INLINE atMost #-}

clamp :: (Ord a) => (a, a) -> a -> a
clamp (lower, upper) = atLeast lower . atMost upper

While their implementations are identical to ‘max’ and ‘min’, semantically they privilege their arguments differently, serving as documentation of intent in code like ‘nonnegative = fmap (atLeast 0)’. The hope is that this may help reduce bugs caused by the common error of mixing up ‘min’ and ‘max’, owing to the unfortunate false friendship between “at least/most” and “the least/most”.


On Sun, Aug 16, 2020 at 2:43 AM Henning Thielemann <[hidden email]> wrote:

On Fri, 14 Aug 2020, Sandy Maguire 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
> ```


https://hackage.haskell.org/package/utility-ht-0.0.15/docs/Data-Ord-HT.html#v:limit
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Jon Purdy
I see a discussion of how the one-sided clamps can be implemented only for floating-point using NaN, but my concern is the API for Ord types generally. ‘clamp (lo, hi) x = min hi (max x lo)’ allows ‘atLeast lo = clamp (lo, 0/0)’ and ‘atMost hi = clamp (0/0, hi)’, which is excellent for providing reasonable NaN handling, but doesn’t say anything about e.g. integers. It does point to the fact that the correct implementations of ‘atLeast’ and ‘atMost’, for consistency with the correct ‘clamp’ for floats, are actually these:

atMost = min
atLeast = flip max -- rather than just ‘max’

To me, that’s another argument that these should be considered, since it’s the kind of subtle distinction that libraries should be handling for users, along the same lines as the stability of ‘min’ & ‘max’ (namely: ‘a == b ==> (min a b, max a b) == (a, b)’). Again, this doesn’t necessarily need to go in the same MR, but they are closely related.

If they were included, it would be necessary to include a note in the documentation that the correct order is ‘atMost hi . atLeast lo’ if someone is applying them separately, but that ‘clamp’ should be preferred for automatically doing this.

I don’t know offhand how this would be disrupted down the line if we changed the ‘Ord’ instance for floats to use the IEEE-754 total ordering, but that should also be considered for all these functions.


On Thu, Aug 27, 2020 at 9:05 AM Carter Schonwald <[hidden email]> wrote:
actually, if you look at the associated ticket, we have a version of clamp that gives the right way to derive the onesided behaviors for even floating point! (and has the correct / desirable behavior in the presence of NANs! )

On Wed, Aug 26, 2020 at 8:38 PM Jon Purdy <[hidden email]> wrote:
I’m also strongly for ‘clamp :: (Ord a) => (a, a) -> a -> a’.

Even if we don’t resolve it now, I do want to mention that, in discussing this with some acquaintances recently, we agreed that one-sided clamps likely warrant a home in ‘Data.Ord’ as well:

atLeast :: (Ord a) => a -> a -> a
atLeast = max
{-# INLINE atLeast #-}

atMost :: (Ord a) => a -> a -> a
atMost = min
{-# INLINE atMost #-}

clamp :: (Ord a) => (a, a) -> a -> a
clamp (lower, upper) = atLeast lower . atMost upper

While their implementations are identical to ‘max’ and ‘min’, semantically they privilege their arguments differently, serving as documentation of intent in code like ‘nonnegative = fmap (atLeast 0)’. The hope is that this may help reduce bugs caused by the common error of mixing up ‘min’ and ‘max’, owing to the unfortunate false friendship between “at least/most” and “the least/most”.


On Sun, Aug 16, 2020 at 2:43 AM Henning Thielemann <[hidden email]> wrote:

On Fri, 14 Aug 2020, Sandy Maguire 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
> ```


https://hackage.haskell.org/package/utility-ht-0.0.15/docs/Data-Ord-HT.html#v:limit
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Carter Schonwald
In reply to this post by Sandy Maguire
Thanks for helping make this happen!

Should be merged In later today! 

On Sat, Aug 15, 2020 at 2:19 PM Sandy Maguire <[hidden email]> wrote:
Sounds good. For whatever reason the tupled arguments make me feel better about the `high<low` having undefined behavior. I'll make the change on the MR.

On Sat, Aug 15, 2020 at 8:22 AM Emily Pillmore <[hidden email]> wrote:
+1, though, David has good points about unnecessary laziness. I'm fine with the name and the signature 

```
clamp :: Ord a ⇒ (a,a) → a → a
```

(or some variation on the theme). 


On Fri, Aug 14, 2020 at 5:38 PM, Sandy Maguire <[hidden email]> wrote:
Hi all,

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.)

Thanks,
Sandy




_______________________________________________




Libraries mailing list




[hidden email]




http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries




_______________________________________________

Libraries mailing list

[hidden email]

http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries


_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Sandy Maguire
My pleasure! Thanks for not letting the experience be a bureaucratic nightmare!

On Fri, Sep 11, 2020 at 11:19 AM Carter Schonwald <[hidden email]> wrote:
Thanks for helping make this happen!

Should be merged In later today! 

On Sat, Aug 15, 2020 at 2:19 PM Sandy Maguire <[hidden email]> wrote:
Sounds good. For whatever reason the tupled arguments make me feel better about the `high<low` having undefined behavior. I'll make the change on the MR.

On Sat, Aug 15, 2020 at 8:22 AM Emily Pillmore <[hidden email]> wrote:
+1, though, David has good points about unnecessary laziness. I'm fine with the name and the signature 

```
clamp :: Ord a ⇒ (a,a) → a → a
```

(or some variation on the theme). 


On Fri, Aug 14, 2020 at 5:38 PM, Sandy Maguire <[hidden email]> wrote:
Hi all,

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.)

Thanks,
Sandy




_______________________________________________




Libraries mailing list




[hidden email]




http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries




_______________________________________________

Libraries mailing list

[hidden email]

http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries


_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: clamp function in base

Carter Schonwald
In reply to this post by Jon Purdy
I totally think these are possibly interesting ideas: could you motivate it as it’s own proposal? There’s some interesting ideas you’re articulating or motivating, but a bit more exposition? 

On Thu, Aug 27, 2020 at 2:34 PM Jon Purdy <[hidden email]> wrote:
I see a discussion of how the one-sided clamps can be implemented only for floating-point using NaN, but my concern is the API for Ord types generally. ‘clamp (lo, hi) x = min hi (max x lo)’ allows ‘atLeast lo = clamp (lo, 0/0)’ and ‘atMost hi = clamp (0/0, hi)’, which is excellent for providing reasonable NaN handling, but doesn’t say anything about e.g. integers. It does point to the fact that the correct implementations of ‘atLeast’ and ‘atMost’, for consistency with the correct ‘clamp’ for floats, are actually these:

atMost = min
atLeast = flip max -- rather than just ‘max’

To me, that’s another argument that these should be considered, since it’s the kind of subtle distinction that libraries should be handling for users, along the same lines as the stability of ‘min’ & ‘max’ (namely: ‘a == b ==> (min a b, max a b) == (a, b)’). Again, this doesn’t necessarily need to go in the same MR, but they are closely related.

If they were included, it would be necessary to include a note in the documentation that the correct order is ‘atMost hi . atLeast lo’ if someone is applying them separately, but that ‘clamp’ should be preferred for automatically doing this.

I don’t know offhand how this would be disrupted down the line if we changed the ‘Ord’ instance for floats to use the IEEE-754 total ordering, but that should also be considered for all these functions.


On Thu, Aug 27, 2020 at 9:05 AM Carter Schonwald <[hidden email]> wrote:
actually, if you look at the associated ticket, we have a version of clamp that gives the right way to derive the onesided behaviors for even floating point! (and has the correct / desirable behavior in the presence of NANs! )

On Wed, Aug 26, 2020 at 8:38 PM Jon Purdy <[hidden email]> wrote:
I’m also strongly for ‘clamp :: (Ord a) => (a, a) -> a -> a’.

Even if we don’t resolve it now, I do want to mention that, in discussing this with some acquaintances recently, we agreed that one-sided clamps likely warrant a home in ‘Data.Ord’ as well:

atLeast :: (Ord a) => a -> a -> a
atLeast = max
{-# INLINE atLeast #-}

atMost :: (Ord a) => a -> a -> a
atMost = min
{-# INLINE atMost #-}

clamp :: (Ord a) => (a, a) -> a -> a
clamp (lower, upper) = atLeast lower . atMost upper

While their implementations are identical to ‘max’ and ‘min’, semantically they privilege their arguments differently, serving as documentation of intent in code like ‘nonnegative = fmap (atLeast 0)’. The hope is that this may help reduce bugs caused by the common error of mixing up ‘min’ and ‘max’, owing to the unfortunate false friendship between “at least/most” and “the least/most”.


On Sun, Aug 16, 2020 at 2:43 AM Henning Thielemann <[hidden email]> wrote:



On Fri, 14 Aug 2020, Sandy Maguire 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


> ```








https://hackage.haskell.org/package/utility-ht-0.0.15/docs/Data-Ord-HT.html#v:limit


_______________________________________________


Libraries mailing list


[hidden email]


http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries




_______________________________________________


Libraries mailing list


[hidden email]


http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries







_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
12