Alternative.some and NonEmpty

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?

On 5 March 2017 at 21:51, 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.
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 Ivan.Miljenovic@gmail.com http://IvanMiljenovic.wordpress.com

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
On 5 March 2017 at 21:51, 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.
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 Ivan.Miljenovic@gmail.com http://IvanMiljenovic.wordpress.com

2017-03-05 13:50 GMT+01:00 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.
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.

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.

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 < lemming@henning-thielemann.de> 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 Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
-- -Andrew Thaddeus Martin

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.

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.

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.

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

2017-03-07 18:11 GMT+01:00 Henning Thielemann : 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.

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
2017-03-07 18:11 GMT+01:00 Henning Thielemann < lemming@henning-thielemann.de>:
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 Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Related:
https://hackage.haskell.org/package/semigroups-0.18.1/docs/src/Data.List.Non...
On Wed, Mar 8, 2017 at 1:18 PM, Edward Kmett
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
wrote: 2017-03-07 18:11 GMT+01:00 Henning Thielemann < lemming@henning-thielemann.de>:
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 Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Even better,
http://hackage.haskell.org/package/base-4.9.1.0/docs/Data-List-NonEmpty.html...
is already there in base! ;)
On Tue, Mar 7, 2017 at 10:21 PM, Tony Morris
Related: https://hackage.haskell.org/package/semigroups-0.18.1/ docs/src/Data.List.NonEmpty.html#some1
On Wed, Mar 8, 2017 at 1:18 PM, Edward Kmett
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
wrote: 2017-03-07 18:11 GMT+01:00 Henning Thielemann < lemming@henning-thielemann.de>:
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 Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

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
Even better,
http://hackage.haskell.org/package/base-4.9.1.0/docs/ Data-List-NonEmpty.html#v:some1
is already there in base! ;)
On Tue, Mar 7, 2017 at 10:21 PM, Tony Morris
wrote: Related: https://hackage.haskell.org/package/semigroups-0.18.1/docs/ src/Data.List.NonEmpty.html#some1
On Wed, Mar 8, 2017 at 1:18 PM, Edward Kmett
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
wrote: 2017-03-07 18:11 GMT+01:00 Henning Thielemann < lemming@henning-thielemann.de>:
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 Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

+1 to either modifying the type as proposed or adding new method of proposed type -1 to status quo, i want this statically checked
participants (9)
-
Andrew Martin
-
Edward Kmett
-
Henning Thielemann
-
Ivan Lazar Miljenovic
-
M Farkas-Dyck
-
Mario Blažević
-
Sven Panne
-
Tony Morris
-
Vladislav Zavialov