Alternative.some and NonEmpty

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

Alternative.some and NonEmpty

Vladislav Zavialov
Since 'Data.List.NonEmpty' is now in 'base', it makes sense to change
the type of 'some' from

some :: Alternative f => f a -> f [a]

to

some :: Alternative f => f a -> f (NonEmpty a)

as it's guaranteed to return a non-empty list.

Currently, both users and implementors of 'Alternative' instances are
at a disadvantage. The users have to use the unsafe NonEmpty.fromList
function to take advantage of the fact that the result of 'some' is
indeed non-empty. The implementors have more space for error - it's
possible to accidentally return an empty list.

I volunteer to implement. Does everyone agree it's a good idea?
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Alternative.some and NonEmpty

Ivan Lazar Miljenovic
On 5 March 2017 at 21:51, Vladislav Zavialov <[hidden email]> wrote:

> Since 'Data.List.NonEmpty' is now in 'base', it makes sense to change
> the type of 'some' from
>
> some :: Alternative f => f a -> f [a]
>
> to
>
> some :: Alternative f => f a -> f (NonEmpty a)
>
> as it's guaranteed to return a non-empty list.
>
> Currently, both users and implementors of 'Alternative' instances are
> at a disadvantage. The users have to use the unsafe NonEmpty.fromList
> function to take advantage of the fact that the result of 'some' is
> indeed non-empty. The implementors have more space for error - it's
> possible to accidentally return an empty list.

The disadvantage is also for people trying to maintain a code base,
though that's solvable with CPP if needed.

However, this also affects the default instances.

(As a user and implementor of Alternative instances, I've never found
myself at a disadvantage for using the current type.)

> I volunteer to implement. Does everyone agree it's a good idea?

I'm -0.5.

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

Re: Alternative.some and NonEmpty

Vladislav Zavialov
> that's solvable with CPP if needed

Note that it's possible to avoid CPP because one can use `fmap toList
. some` to achieve the old behavior. And the breakage is not silent,
so it won't be too hard for maintainers.

On Sun, Mar 5, 2017 at 2:49 PM, Ivan Lazar Miljenovic
<[hidden email]> wrote:

> On 5 March 2017 at 21:51, Vladislav Zavialov <[hidden email]> wrote:
>> Since 'Data.List.NonEmpty' is now in 'base', it makes sense to change
>> the type of 'some' from
>>
>> some :: Alternative f => f a -> f [a]
>>
>> to
>>
>> some :: Alternative f => f a -> f (NonEmpty a)
>>
>> as it's guaranteed to return a non-empty list.
>>
>> Currently, both users and implementors of 'Alternative' instances are
>> at a disadvantage. The users have to use the unsafe NonEmpty.fromList
>> function to take advantage of the fact that the result of 'some' is
>> indeed non-empty. The implementors have more space for error - it's
>> possible to accidentally return an empty list.
>
> The disadvantage is also for people trying to maintain a code base,
> though that's solvable with CPP if needed.
>
> However, this also affects the default instances.
>
> (As a user and implementor of Alternative instances, I've never found
> myself at a disadvantage for using the current type.)
>
>> I volunteer to implement. Does everyone agree it's a good idea?
>
> I'm -0.5.
>
> --
> Ivan Lazar Miljenovic
> [hidden email]
> http://IvanMiljenovic.wordpress.com
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Alternative.some and NonEmpty

Sven Panne-2
2017-03-05 13:50 GMT+01:00 Vladislav Zavialov <[hidden email]>:
> that's solvable with CPP if needed

Note that it's possible to avoid CPP because one can use `fmap toList
. some` to achieve the old behavior. And the breakage is not silent,
so it won't be too hard for maintainers.

IMHO it's basically irrelevant if you would need CPP or could do it in plain Haskell, the main point is: It is an incompatible, breaking change which must be acted upon by maintainers. An ongoing stream of such tiny changes results in a non-trivial amount of work if you want to keep your projects up-to-date.

A much better approach is to bundle such changes and discuss them, come up with a good migration story, implement things and release them, all under a common theme. In our case, it would be something like "use NonEmpty in base and some central packages wherever it makes sense", *if* that is what people want.

I'm basically neutral about the proposed change itself, but I'm -1 if it is considered in isolation.

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

Re: Alternative.some and NonEmpty

Henning Thielemann
In reply to this post by Vladislav Zavialov

On Sun, 5 Mar 2017, Vladislav Zavialov wrote:

> Since 'Data.List.NonEmpty' is now in 'base', it makes sense to change
> the type of 'some' from
>
> some :: Alternative f => f a -> f [a]
>
> to
>
> some :: Alternative f => f a -> f (NonEmpty a)
>
> as it's guaranteed to return a non-empty list.

A less invasive way would be to add a new function with that type.
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Alternative.some and NonEmpty

Andrew Martin
I would be in favor of adding the new function and against changing the type signature of the existing one. The breakage from changing it would just be too great.

-Andrew Martin

On Mon, Mar 6, 2017 at 3:39 AM, Henning Thielemann <[hidden email]> wrote:

On Sun, 5 Mar 2017, Vladislav Zavialov wrote:

Since 'Data.List.NonEmpty' is now in 'base', it makes sense to change
the type of 'some' from

some :: Alternative f => f a -> f [a]

to

some :: Alternative f => f a -> f (NonEmpty a)

as it's guaranteed to return a non-empty list.

A less invasive way would be to add a new function with that type.

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



--
-Andrew Thaddeus Martin

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

Re: Alternative.some and NonEmpty

Mario Blazevic-2
In reply to this post by Henning Thielemann
On 2017-03-06 03:39 AM, Henning Thielemann wrote:

>
> On Sun, 5 Mar 2017, Vladislav Zavialov wrote:
>
>> Since 'Data.List.NonEmpty' is now in 'base', it makes sense to change
>> the type of 'some' from
>>
>> some :: Alternative f => f a -> f [a]
>>
>> to
>>
>> some :: Alternative f => f a -> f (NonEmpty a)
>>
>> as it's guaranteed to return a non-empty list.
>
> A less invasive way would be to add a new function with that type.

If we're adding a new function, it might make more sense to add
something more generic, like

genericMany, genericSome ::
   (Alternative f, Applicative m, Monoid m) => f a -> f (m a)

The expected type of these operations is usually fixed on the client side.

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

Re: Alternative.some and NonEmpty

Henning Thielemann

On Tue, 7 Mar 2017, Mario Blažević wrote:

> If we're adding a new function, it might make more sense to add
> something more generic, like
>
> genericMany, genericSome ::
>   (Alternative f, Applicative m, Monoid m) => f a -> f (m a)
>
> The expected type of these operations is usually fixed on the client side.

I think it must be Monoid (m a). But it won't work, because NonEmpty is no
Monoid because there is no mempty.
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Alternative.some and NonEmpty

Mario Blazevic-2
On 2017-03-07 11:40 AM, Henning Thielemann wrote:

>
> On Tue, 7 Mar 2017, Mario Blažević wrote:
>
>> If we're adding a new function, it might make more sense to add
>> something more generic, like
>>
>> genericMany, genericSome ::
>>   (Alternative f, Applicative m, Monoid m) => f a -> f (m a)
>>
>> The expected type of these operations is usually fixed on the client
>> side.
>
> I think it must be Monoid (m a). But it won't work, because NonEmpty is
> no Monoid because there is no mempty.

You're correct on both counts, sorry about that. It would have to be

genericMany, genericSome ::
   (Alternative f, Applicative m, Semigroup (m a)) => f a -> f (m a)

once Semigroup is in base.

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

Re: Alternative.some and NonEmpty

M Farkas-Dyck-2
In reply to this post by Vladislav Zavialov
+1 to either modifying the type as proposed or adding new method of
proposed type

-1 to status quo, i want this statically checked
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Alternative.some and NonEmpty

Henning Thielemann
In reply to this post by Mario Blazevic-2

On Tue, 7 Mar 2017, Mario Blažević wrote:

> On 2017-03-07 11:40 AM, Henning Thielemann wrote:
>
>> I think it must be Monoid (m a). But it won't work, because NonEmpty is
>> no Monoid because there is no mempty.
>
> You're correct on both counts, sorry about that. It would have to be
>
> genericMany, genericSome ::
>  (Alternative f, Applicative m, Semigroup (m a)) => f a -> f (m a)
>
> once Semigroup is in base.
But then, for genericMany, Monoid would be appropriate, again. :-)
_______________________________________________
Libraries mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
Reply | Threaded
Open this post in threaded view
|

Re: Alternative.some and NonEmpty

Sven Panne-2
2017-03-07 18:11 GMT+01:00 Henning Thielemann <[hidden email]>:

On Tue, 7 Mar 2017, Mario Blažević wrote:
[...]You're correct on both counts, sorry about that. It would have to be

genericMany, genericSome ::
 (Alternative f, Applicative m, Semigroup (m a)) => f a -> f (m a)

once Semigroup is in base.

But then, for genericMany, Monoid would be appropriate, again. :-)

I think this discussion alone is enough of a hint that there is a need for a broader discussion to come up with coherent story regarding NonEmpty in general. ;-) Focusing on one or two functions alone will probably do more harm than improve the overall situation.

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

Re: Alternative.some and NonEmpty

Edward Kmett-2
I'm also in the "if we're going to do this, it should probably be a new function" camp. e.g. `some1`. I'm kinda neutral on adding it at all at this point, but if we do it, it should probably be done along these lines.

As for using a semigroup based implementation, its performance is, sadly, rather awful for constructing `NonEmpty` lists, and more damning, you have no law relating the 'pure' or whatever you're using to create values and the Semigroup you're using to glue them together, so it only works for NonEmpty on a purely ad-hoc type-by-type basis. That signature isn't one we want as evidenced by the fact that if you pick m = Maybe you sure as heck won't get anything like what you expect! This is the pointed problem all over again. I'm very strongly -1 on that variant of the proposal.

-Edward


On Tue, Mar 7, 2017 at 2:02 PM, Sven Panne <[hidden email]> wrote:
2017-03-07 18:11 GMT+01:00 Henning Thielemann <[hidden email]>:

On Tue, 7 Mar 2017, Mario Blažević wrote:
[...]You're correct on both counts, sorry about that. It would have to be

genericMany, genericSome ::
 (Alternative f, Applicative m, Semigroup (m a)) => f a -> f (m a)

once Semigroup is in base.

But then, for genericMany, Monoid would be appropriate, again. :-)

I think this discussion alone is enough of a hint that there is a need for a broader discussion to come up with coherent story regarding NonEmpty in general. ;-) Focusing on one or two functions alone will probably do more harm than improve the overall situation.

_______________________________________________
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: Alternative.some and NonEmpty

Tony Morris

On Wed, Mar 8, 2017 at 1:18 PM, Edward Kmett <[hidden email]> wrote:
I'm also in the "if we're going to do this, it should probably be a new function" camp. e.g. `some1`. I'm kinda neutral on adding it at all at this point, but if we do it, it should probably be done along these lines.

As for using a semigroup based implementation, its performance is, sadly, rather awful for constructing `NonEmpty` lists, and more damning, you have no law relating the 'pure' or whatever you're using to create values and the Semigroup you're using to glue them together, so it only works for NonEmpty on a purely ad-hoc type-by-type basis. That signature isn't one we want as evidenced by the fact that if you pick m = Maybe you sure as heck won't get anything like what you expect! This is the pointed problem all over again. I'm very strongly -1 on that variant of the proposal.

-Edward


On Tue, Mar 7, 2017 at 2:02 PM, Sven Panne <[hidden email]> wrote:
2017-03-07 18:11 GMT+01:00 Henning Thielemann <[hidden email]>:

On Tue, 7 Mar 2017, Mario Blažević wrote:
[...]You're correct on both counts, sorry about that. It would have to be

genericMany, genericSome ::
 (Alternative f, Applicative m, Semigroup (m a)) => f a -> f (m a)

once Semigroup is in base.

But then, for genericMany, Monoid would be appropriate, again. :-)

I think this discussion alone is enough of a hint that there is a need for a broader discussion to come up with coherent story regarding NonEmpty in general. ;-) Focusing on one or two functions alone will probably do more harm than improve the overall situation.

_______________________________________________
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: Alternative.some and NonEmpty

Edward Kmett-2

On Tue, Mar 7, 2017 at 10:21 PM, Tony Morris <[hidden email]> wrote:

On Wed, Mar 8, 2017 at 1:18 PM, Edward Kmett <[hidden email]> wrote:
I'm also in the "if we're going to do this, it should probably be a new function" camp. e.g. `some1`. I'm kinda neutral on adding it at all at this point, but if we do it, it should probably be done along these lines.

As for using a semigroup based implementation, its performance is, sadly, rather awful for constructing `NonEmpty` lists, and more damning, you have no law relating the 'pure' or whatever you're using to create values and the Semigroup you're using to glue them together, so it only works for NonEmpty on a purely ad-hoc type-by-type basis. That signature isn't one we want as evidenced by the fact that if you pick m = Maybe you sure as heck won't get anything like what you expect! This is the pointed problem all over again. I'm very strongly -1 on that variant of the proposal.

-Edward


On Tue, Mar 7, 2017 at 2:02 PM, Sven Panne <[hidden email]> wrote:
2017-03-07 18:11 GMT+01:00 Henning Thielemann <[hidden email]>:

On Tue, 7 Mar 2017, Mario Blažević wrote:
[...]You're correct on both counts, sorry about that. It would have to be

genericMany, genericSome ::
 (Alternative f, Applicative m, Semigroup (m a)) => f a -> f (m a)

once Semigroup is in base.

But then, for genericMany, Monoid would be appropriate, again. :-)

I think this discussion alone is enough of a hint that there is a need for a broader discussion to come up with coherent story regarding NonEmpty in general. ;-) Focusing on one or two functions alone will probably do more harm than improve the overall situation.

_______________________________________________
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: Alternative.some and NonEmpty

Tony Morris
Ha!

I saw that a while back, was pleasantly surprised, then went ahead and forgot about it. Thanks for the surprise again. Two for the price of one.


On Thu, Mar 9, 2017 at 2:19 PM, Edward Kmett <[hidden email]> wrote:

On Tue, Mar 7, 2017 at 10:21 PM, Tony Morris <[hidden email]> wrote:

On Wed, Mar 8, 2017 at 1:18 PM, Edward Kmett <[hidden email]> wrote:
I'm also in the "if we're going to do this, it should probably be a new function" camp. e.g. `some1`. I'm kinda neutral on adding it at all at this point, but if we do it, it should probably be done along these lines.

As for using a semigroup based implementation, its performance is, sadly, rather awful for constructing `NonEmpty` lists, and more damning, you have no law relating the 'pure' or whatever you're using to create values and the Semigroup you're using to glue them together, so it only works for NonEmpty on a purely ad-hoc type-by-type basis. That signature isn't one we want as evidenced by the fact that if you pick m = Maybe you sure as heck won't get anything like what you expect! This is the pointed problem all over again. I'm very strongly -1 on that variant of the proposal.

-Edward


On Tue, Mar 7, 2017 at 2:02 PM, Sven Panne <[hidden email]> wrote:
2017-03-07 18:11 GMT+01:00 Henning Thielemann <[hidden email]>:

On Tue, 7 Mar 2017, Mario Blažević wrote:
[...]You're correct on both counts, sorry about that. It would have to be

genericMany, genericSome ::
 (Alternative f, Applicative m, Semigroup (m a)) => f a -> f (m a)

once Semigroup is in base.

But then, for genericMany, Monoid would be appropriate, again. :-)

I think this discussion alone is enough of a hint that there is a need for a broader discussion to come up with coherent story regarding NonEmpty in general. ;-) Focusing on one or two functions alone will probably do more harm than improve the overall situation.

_______________________________________________
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