Fwd: Proposal: Add singleton function to Data.List module

Am Mi., 21. Aug. 2019 um 12:22 Uhr schrieb Nathan Bouscal < nbouscal@gmail.com>:
I would strongly encourage anyone inclined to say things like “there's no benefit in having the function” to consider reframing the sentiment as “I wouldn’t benefit from having the function, and don’t understand the benefit others will gain.” Once you’ve done that reframe, you can notice that there’s a lack of understanding toward which the appropriate emotional stance is curiosity, not dismissiveness. A lot of people have clearly expressed in this thread that they would benefit from this function, and when you assert as fact that such benefit does not exist, you’re implicitly dismissing and devaluing their experience. [...]
There is also another side of the coin: A lot of people have clearly expressed counterarguments, so *their* experience has been equally "dismissed" or "devalued". Reframing the discussion shouldn't be biased, otherwise it's just a cheap trick to make one side of the discussion more valuable/stronger. Furthermore, a technical discussion doesn't need to be an excercise in nonviolent communication, as long as people don't start insulting each other. I think the main problem of this discussion (and other similar threads on this list) is that there is no consensus about how to design an API. IMHO, piling up little helpers just because they came up in a few places is a recipe for horrible, bloated APIs. The questions one should ask are "Does it generalize things?", "Does it make my API more powerful?" (i.e. can I do things I couldn't do before), "Does it remove common pitfalls?" etc. But this is just my personal view, obviously others seem to disagree.... :-/

On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
I think the main problem of this discussion (and other similar threads on this list) is that there is no consensus about how to design an API. IMHO, piling up little helpers just because they came up in a few places is a recipe for horrible, bloated APIs. The questions one should ask are "Does it generalize things?", "Does it make my API more powerful?" (i.e. can I do things I couldn't do before), "Does it remove common pitfalls?" etc. But this is just my personal view, obviously others seem to disagree.... :-/
I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. https://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.Base.html#lin... We define a monomorphic function for this operation, we just hide it in the implementation of the typeclass instance; we do this frequently, intentionally making a monomorphic function inaccessible to the user unless it's called in a polymorphic context (and, if they want to intentionally monomorphise it, require using an extension - type applications - which is particularly ugly/inconvenient for operators like `>>=`.) I think this is unfortunate as a general design choice; the user of a library should have the flexibility to choose, not be forced into one or the other. For [] we have the robot monkey operator, and this is an idiom that people can become familiar with - but it does not appear natively in any documentation; it is a partially applied constructor rather than a top-level function. My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context. Kris

In (my) most to least preferred:
* NonEmpty#singleton
*
On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think the main problem of this discussion (and other similar threads on this list) is that there is no consensus about how to design an API. IMHO, piling up little helpers just because they came up in a few places is a recipe for horrible, bloated APIs. The questions one should ask are "Does it generalize things?", "Does it make my API more powerful?" (i.e. can I do things I couldn't do before), "Does it remove common pitfalls?" etc. But this is just my personal view, obviously others seem to disagree.... :-/
I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts.
https://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.Base.html#lin...
We define a monomorphic function for this operation, we just hide it in the implementation of the typeclass instance; we do this frequently, intentionally making a monomorphic function inaccessible to the user unless it's called in a polymorphic context (and, if they want to intentionally monomorphise it, require using an extension - type applications - which is particularly ugly/inconvenient for operators like `>>=`.) I think this is unfortunate as a general design choice; the user of a library should have the flexibility to choose, not be forced into one or the other. For [] we have the robot monkey operator, and this is an idiom that people can become familiar with - but it does not appear natively in any documentation; it is a partially applied constructor rather than a top-level function.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
Kris _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Why hasn't anyone noticed that the singleton function for NonEmpty is just
a monkey robot with a mustache? (:|[])
Also, pure works perfectly fine here as well.
On Thu, Aug 22, 2019, 17:52 Tony Morris
In (my) most to least preferred:
* NonEmpty#singleton *
* []#singleton On Fri, Aug 23, 2019 at 3:12 AM Kris Nuttycombe
wrote: On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think the main problem of this discussion (and other similar threads on this list) is that there is no consensus about how to design an API. IMHO, piling up little helpers just because they came up in a few places is a recipe for horrible, bloated APIs. The questions one should ask are "Does it generalize things?", "Does it make my API more powerful?" (i.e. can I do things I couldn't do before), "Does it remove common pitfalls?" etc. But this is just my personal view, obviously others seem to disagree.... :-/
I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts.
https://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.Base.html#lin...
We define a monomorphic function for this operation, we just hide it in the implementation of the typeclass instance; we do this frequently, intentionally making a monomorphic function inaccessible to the user unless it's called in a polymorphic context (and, if they want to intentionally monomorphise it, require using an extension - type applications - which is particularly ugly/inconvenient for operators like `>>=`.) I think this is unfortunate as a general design choice; the user of a library should have the flexibility to choose, not be forced into one or the other. For [] we have the robot monkey operator, and this is an idiom that people can become familiar with - but it does not appear natively in any documentation; it is a partially applied constructor rather than a top-level function.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
Kris _______________________________________________ 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

Am Do., 22. Aug. 2019 um 19:11 Uhr schrieb Kris Nuttycombe < kris.nuttycombe@gmail.com>:
On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. [...]
I think we can agree that we disagree here. ;-) My brain is too small to remember the names of myriads of trivial helpers, so I very much prefer general, orthogonal things. In our case: If we have a general, polymorphic function (often from a type class), just use that. If for some reason (rarely!) I want a more monomorphic function, I can just add a plain old type signature somewhere (no need for funky language extensions like type applications). This radically reduces the number of things one has to remember. In our case: Know type classes + know a way to make things more monomorphic.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
This is exactly the opposite API design principle I have: Do not expose the monomorphic functions if they are already in a type class. You can easily reconstruct them as a library user via type signtures if this is really needed (still haven't seen many convincing examples of that), but you can' do it the other way round. Less things exposed, no generality/use cases lost => easier to remember. The thing we can probably agree on: API design is hard and it's not an exact science, more a kind of art which is assessed in a subjective way... :-)

It has been two weeks since I submitted this proposal, and one week since the core library committee started deliberating behind closed doors. Is there any visibility into the CLC's process, or at the very least a rough expected timeline? On Fri, Aug 23, 2019, at 3:57 AM, Sven Panne wrote:
Am Do., 22. Aug. 2019 um 19:11 Uhr schrieb Kris Nuttycombe
: On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. [...]
I think we can agree that we disagree here. ;-) My brain is too small to remember the names of myriads of trivial helpers, so I very much prefer general, orthogonal things. In our case: If we have a general, polymorphic function (often from a type class), just use that. If for some reason (rarely!) I want a more monomorphic function, I can just add a plain old type signature somewhere (no need for funky language extensions like type applications). This radically reduces the number of things one has to remember. In our case: Know type classes + know a way to make things more monomorphic.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
This is exactly the opposite API design principle I have: Do not expose the monomorphic functions if they are already in a type class. You can easily reconstruct them as a library user via type signtures if this is really needed (still haven't seen many convincing examples of that), but you can' do it the other way round. Less things exposed, no generality/use cases lost => easier to remember.
The thing we can probably agree on: API design is hard and it's not an exact science, more a kind of art which is assessed in a subjective way... :-)
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

For what it's worth, when starting out I found the disconnect between list sugar and list constructor/destructors extremely confusing.
In retrospect it seems pretty silly, but I could not figure out how lists were consumed as (x : xs) but often produced with [x, x1, ...]. Mistakes like [x, xs] were common.
When I finally realized that I could construct lists with the list constuctors, I started using them exclusively.
Simplcity and straightforwardness help understanding. It was much easier for me to understand a singleton list as (x : []) than [x]. Having to deal with '(singleton x)' (at the time not knowing the definition of 'singleton') would have been another layer of confusion.
I get that 'singleton' is library design, since in shows up in Map, Array, Set, etc. But for me trying to use lists, it would have only been useful if I defined it myself as a way to learn that constuctors are fuctions, and that 'singleton' means 'single'.
On August 23, 2019 7:56:41 AM UTC, Sven Panne
Am Do., 22. Aug. 2019 um 19:11 Uhr schrieb Kris Nuttycombe < kris.nuttycombe@gmail.com>:
On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. [...]
I think we can agree that we disagree here. ;-) My brain is too small to remember the names of myriads of trivial helpers, so I very much prefer general, orthogonal things. In our case: If we have a general, polymorphic function (often from a type class), just use that. If for some reason (rarely!) I want a more monomorphic function, I can just add a plain old type signature somewhere (no need for funky language extensions like type applications). This radically reduces the number of things one has to remember. In our case: Know type classes + know a way to make things more monomorphic.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
This is exactly the opposite API design principle I have: Do not expose the monomorphic functions if they are already in a type class. You can easily reconstruct them as a library user via type signtures if this is really needed (still haven't seen many convincing examples of that), but you can' do it the other way round. Less things exposed, no generality/use cases lost => easier to remember.
The thing we can probably agree on: API design is hard and it's not an exact science, more a kind of art which is assessed in a subjective way... :-)
Keith -- Sent from my Android device with K-9 Mail. Please excuse my brevity.

I'm still waiting to hear anything at all from the CLC. In the meantime I published the list-singleton library to provide this function: https://taylor.fausak.me/2019/09/07/list-singleton/ On Wed, Aug 28, 2019, at 3:57 PM, Keith wrote:
For what it's worth, when starting out I found the disconnect between list sugar and list constructor/destructors extremely confusing. In retrospect it seems pretty silly, but I could not figure out how lists were consumed as (x : xs) but often produced with [x, x1, ...]. Mistakes like [x, xs] were common. When I finally realized that I could construct lists with the list constuctors, I started using them exclusively.
Simplcity and straightforwardness help understanding. It was much easier for me to understand a singleton list as (x : []) than [x]. Having to deal with '(singleton x)' (at the time not knowing the definition of 'singleton') would have been another layer of confusion.
I get that 'singleton' is library design, since in shows up in Map, Array, Set, etc. But for me trying to use lists, it would have only been useful if I defined it myself as a way to learn that constuctors are fuctions, and that 'singleton' means 'single'.
On August 23, 2019 7:56:41 AM UTC, Sven Panne
wrote: Am Do., 22. Aug. 2019 um 19:11 Uhr schrieb Kris Nuttycombe
: On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. [...]
I think we can agree that we disagree here. ;-) My brain is too small to remember the names of myriads of trivial helpers, so I very much prefer general, orthogonal things. In our case: If we have a general, polymorphic function (often from a type class), just use that. If for some reason (rarely!) I want a more monomorphic function, I can just add a plain old type signature somewhere (no need for funky language extensions like type applications). This radically reduces the number of things one has to remember. In our case: Know type classes + know a way to make things more monomorphic.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
This is exactly the opposite API design principle I have: Do not expose the monomorphic functions if they are already in a type class. You can easily reconstruct them as a library user via type signtures if this is really needed (still haven't seen many convincing examples of that), but you can' do it the other way round. Less things exposed, no generality/use cases lost => easier to remember.
The thing we can probably agree on: API design is hard and it's not an exact science, more a kind of art which is assessed in a subjective way... :-)
Keith -- Sent from my Android device with K-9 Mail. Please excuse my brevity. _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

To grant some insight into what is going on behind closed doors. I figured
I'd unpack a bit of it here.
The current resolution is to treat this as step one in a longer maneuver.
*We'll be adding *singleton* to *Data.List*, immediately.*
The headache has really been the issue mentioned above wherein Data.List
has historically been treated as an unqualified export that shouldn't clash
with the Prelude in any way.
This is mostly a historical accident and doesn't really match up with the
way any of the other "container" like modules are expected to be used. It
has led to the somewhat messy state of dozens of other combinators in Data.List
such as foldr having to be generalized by the Foldable/Traversable Proposal
and other language warts starting to accumulate over time. It is
disproportionately difficult to add things to Data.List, so we're going to
fix that. -- We'd intended to fix that wart since GHC 7.10, but lacked a
sufficient forcing function. Expanding the API of Data.List is acting as
that forcing function.
*We are going to be switching the usage pattern for *Data.List* to expect a
qualified or explicit import list like *Data.Text, Data.ByteString, Data.Set
,* etc.*
This also helps allow for easier expansion of Data.List, which has been
pretty stagnant other than a non-report-specified uncons slipping in
stealthily in GHC 7.10.
It also helps ameliorate any long term concerns with this taking a name, as
it is now something placed in a module where name collisions are okay, as
usage is qualified or explicit. Meanwhile, Ryan GL Scott managed to
accumulate enough data to show that breakage this one combinator would
introduce was pretty minor after all, so we're going to go ahead with
adding singleton before the rest of this happens.
To get *there*, we'll need a slightly longer timeline, and some support
from GHC HQ to craft an appropriate warning. This will allow us to
monomorphize the combinators in Data.List yielding a sane ending state that
doesn't require a PhD in the History of Haskell to fully understand, and
we'll be able to retire GHC.OldList once an appropriate 3-release policy
compatible migration plan has been fully hammered out.
Normally, I'd wait until we had a full plan with all the migration issues
posted rather than shooting off half-cocked like this, but I wanted to be
clear about what was causing the communication delay.
-Edward
On Wed, Aug 28, 2019 at 12:57 PM Keith
For what it's worth, when starting out I found the disconnect between list sugar and list constructor/destructors extremely confusing. In retrospect it seems pretty silly, but I could not figure out how lists were consumed as (x : xs) but often produced with [x, x1, ...]. Mistakes like [x, xs] were common. When I finally realized that I could construct lists with the list constuctors, I started using them exclusively.
Simplcity and straightforwardness help understanding. It was much easier for me to understand a singleton list as (x : []) than [x]. Having to deal with '(singleton x)' (at the time not knowing the definition of 'singleton') would have been another layer of confusion.
I get that 'singleton' is library design, since in shows up in Map, Array, Set, etc. But for me trying to use lists, it would have only been useful if I defined it myself as a way to learn that constuctors are fuctions, and that 'singleton' means 'single'.
On August 23, 2019 7:56:41 AM UTC, Sven Panne
wrote: Am Do., 22. Aug. 2019 um 19:11 Uhr schrieb Kris Nuttycombe < kris.nuttycombe@gmail.com>:
On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. [...]
I think we can agree that we disagree here. ;-) My brain is too small to remember the names of myriads of trivial helpers, so I very much prefer general, orthogonal things. In our case: If we have a general, polymorphic function (often from a type class), just use that. If for some reason (rarely!) I want a more monomorphic function, I can just add a plain old type signature somewhere (no need for funky language extensions like type applications). This radically reduces the number of things one has to remember. In our case: Know type classes + know a way to make things more monomorphic.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
This is exactly the opposite API design principle I have: Do not expose the monomorphic functions if they are already in a type class. You can easily reconstruct them as a library user via type signtures if this is really needed (still haven't seen many convincing examples of that), but you can' do it the other way round. Less things exposed, no generality/use cases lost => easier to remember.
The thing we can probably agree on: API design is hard and it's not an exact science, more a kind of art which is assessed in a subjective way... :-)
Keith -- Sent from my Android device with K-9 Mail. Please excuse my brevity. _______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

Am So., 8. Sept. 2019 um 05:59 Uhr schrieb Edward Kmett
To grant some insight into what is going on behind closed doors. I figured I'd unpack a bit of it here.
Why is it necessary this gets discussed behind closed doors in the first place? Why can't we get more insight into the decision process of such a highly controversial proposal?
The current resolution is to treat this as step one in a longer maneuver.
*We'll be adding *singleton* to *Data.List*, immediately.*
The headache has really been the issue mentioned above wherein Data.List has historically been treated as an unqualified export that shouldn't clash with the Prelude in any way.
This is mostly a historical accident and doesn't really match up with the way any of the other "container" like modules are expected to be used. It has led to the somewhat messy state of dozens of other combinators in Data.List such as foldr having to be generalized by the Foldable/Traversable Proposal and other language warts starting to accumulate over time. It is disproportionately difficult to add things to Data.List, so we're going to fix that. -- We'd intended to fix that wart since GHC 7.10, but lacked a sufficient forcing function. Expanding the API of Data.List is acting as that forcing function.
*We are going to be switching the usage pattern for *Data.List* to expect a qualified or explicit import list like *Data.Text, Data.ByteString, Data.Set,* etc.*
This also helps allow for easier expansion of Data.List, which has been pretty stagnant other than a non-report-specified uncons slipping in stealthily in GHC 7.10.
It also helps ameliorate any long term concerns with this taking a name, as it is now something placed in a module where name collisions are okay, as usage is qualified or explicit. Meanwhile, Ryan GL Scott managed to accumulate enough data to show that breakage this one combinator would introduce was pretty minor after all, so we're going to go ahead with adding singleton before the rest of this happens.
To get *there*, we'll need a slightly longer timeline, and some support from GHC HQ to craft an appropriate warning. This will allow us to monomorphize the combinators in Data.List yielding a sane ending state that doesn't require a PhD in the History of Haskell to fully understand, and we'll be able to retire GHC.OldList once an appropriate 3-release policy compatible migration plan has been fully hammered out.
Normally, I'd wait until we had a full plan with all the migration issues posted rather than shooting off half-cocked like this, but I wanted to be clear about what was causing the communication delay.
-Edward
On Wed, Aug 28, 2019 at 12:57 PM Keith
wrote: For what it's worth, when starting out I found the disconnect between list sugar and list constructor/destructors extremely confusing. In retrospect it seems pretty silly, but I could not figure out how lists were consumed as (x : xs) but often produced with [x, x1, ...]. Mistakes like [x, xs] were common. When I finally realized that I could construct lists with the list constuctors, I started using them exclusively.
Simplcity and straightforwardness help understanding. It was much easier for me to understand a singleton list as (x : []) than [x]. Having to deal with '(singleton x)' (at the time not knowing the definition of 'singleton') would have been another layer of confusion.
I get that 'singleton' is library design, since in shows up in Map, Array, Set, etc. But for me trying to use lists, it would have only been useful if I defined it myself as a way to learn that constuctors are fuctions, and that 'singleton' means 'single'.
On August 23, 2019 7:56:41 AM UTC, Sven Panne
wrote: Am Do., 22. Aug. 2019 um 19:11 Uhr schrieb Kris Nuttycombe < kris.nuttycombe@gmail.com>:
On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. [...]
I think we can agree that we disagree here. ;-) My brain is too small to remember the names of myriads of trivial helpers, so I very much prefer general, orthogonal things. In our case: If we have a general, polymorphic function (often from a type class), just use that. If for some reason (rarely!) I want a more monomorphic function, I can just add a plain old type signature somewhere (no need for funky language extensions like type applications). This radically reduces the number of things one has to remember. In our case: Know type classes + know a way to make things more monomorphic.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
This is exactly the opposite API design principle I have: Do not expose the monomorphic functions if they are already in a type class. You can easily reconstruct them as a library user via type signtures if this is really needed (still haven't seen many convincing examples of that), but you can' do it the other way round. Less things exposed, no generality/use cases lost => easier to remember.
The thing we can probably agree on: API design is hard and it's not an exact science, more a kind of art which is assessed in a subjective way... :-)
Keith -- Sent from my Android device with K-9 Mail. Please excuse my brevity. _______________________________________________ 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

https://groups.google.com/forum/#!forum/haskell-core-libraries should link to the CLC mailing list archive. As far as I can tell it should be public. -Edward On Sat, Sep 7, 2019 at 11:53 PM Helmut Schmidt < helmut.schmidt.4711@gmail.com> wrote:
Am So., 8. Sept. 2019 um 05:59 Uhr schrieb Edward Kmett
:
To grant some insight into what is going on behind closed doors. I figured I'd unpack a bit of it here.
Why is it necessary this gets discussed behind closed doors in the first place? Why can't we get more insight into the decision process of such a highly controversial proposal?
The current resolution is to treat this as step one in a longer maneuver.
*We'll be adding *singleton* to *Data.List*, immediately.*
The headache has really been the issue mentioned above wherein Data.List has historically been treated as an unqualified export that shouldn't clash with the Prelude in any way.
This is mostly a historical accident and doesn't really match up with the way any of the other "container" like modules are expected to be used. It has led to the somewhat messy state of dozens of other combinators in Data.List such as foldr having to be generalized by the Foldable/Traversable Proposal and other language warts starting to accumulate over time. It is disproportionately difficult to add things to Data.List, so we're going to fix that. -- We'd intended to fix that wart since GHC 7.10, but lacked a sufficient forcing function. Expanding the API of Data.List is acting as that forcing function.
*We are going to be switching the usage pattern for *Data.List* to expect a qualified or explicit import list like *Data.Text, Data.ByteString, Data.Set,* etc.*
This also helps allow for easier expansion of Data.List, which has been pretty stagnant other than a non-report-specified uncons slipping in stealthily in GHC 7.10.
It also helps ameliorate any long term concerns with this taking a name, as it is now something placed in a module where name collisions are okay, as usage is qualified or explicit. Meanwhile, Ryan GL Scott managed to accumulate enough data to show that breakage this one combinator would introduce was pretty minor after all, so we're going to go ahead with adding singleton before the rest of this happens.
To get *there*, we'll need a slightly longer timeline, and some support from GHC HQ to craft an appropriate warning. This will allow us to monomorphize the combinators in Data.List yielding a sane ending state that doesn't require a PhD in the History of Haskell to fully understand, and we'll be able to retire GHC.OldList once an appropriate 3-release policy compatible migration plan has been fully hammered out.
Normally, I'd wait until we had a full plan with all the migration issues posted rather than shooting off half-cocked like this, but I wanted to be clear about what was causing the communication delay.
-Edward
On Wed, Aug 28, 2019 at 12:57 PM Keith
wrote: For what it's worth, when starting out I found the disconnect between list sugar and list constructor/destructors extremely confusing. In retrospect it seems pretty silly, but I could not figure out how lists were consumed as (x : xs) but often produced with [x, x1, ...]. Mistakes like [x, xs] were common. When I finally realized that I could construct lists with the list constuctors, I started using them exclusively.
Simplcity and straightforwardness help understanding. It was much easier for me to understand a singleton list as (x : []) than [x]. Having to deal with '(singleton x)' (at the time not knowing the definition of 'singleton') would have been another layer of confusion.
I get that 'singleton' is library design, since in shows up in Map, Array, Set, etc. But for me trying to use lists, it would have only been useful if I defined it myself as a way to learn that constuctors are fuctions, and that 'singleton' means 'single'.
On August 23, 2019 7:56:41 AM UTC, Sven Panne
wrote: Am Do., 22. Aug. 2019 um 19:11 Uhr schrieb Kris Nuttycombe < kris.nuttycombe@gmail.com>:
On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. [...]
I think we can agree that we disagree here. ;-) My brain is too small to remember the names of myriads of trivial helpers, so I very much prefer general, orthogonal things. In our case: If we have a general, polymorphic function (often from a type class), just use that. If for some reason (rarely!) I want a more monomorphic function, I can just add a plain old type signature somewhere (no need for funky language extensions like type applications). This radically reduces the number of things one has to remember. In our case: Know type classes + know a way to make things more monomorphic.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
This is exactly the opposite API design principle I have: Do not expose the monomorphic functions if they are already in a type class. You can easily reconstruct them as a library user via type signtures if this is really needed (still haven't seen many convincing examples of that), but you can' do it the other way round. Less things exposed, no generality/use cases lost => easier to remember.
The thing we can probably agree on: API design is hard and it's not an exact science, more a kind of art which is assessed in a subjective way... :-)
Keith -- Sent from my Android device with K-9 Mail. Please excuse my brevity. _______________________________________________ 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

Hooray! I'm happy to hear that my proposal has been accepted and `singleton` will be added to `Data.List` in the next major release of GHC. I'm also excited about making functions in `Data.List` monomorphic to lists. I look forward to that change! I'd like to take a moment to thank my team at ITProTV for motivating this proposal. I'd also like to thank the community, both here and elsewhere, for the spirited discussion about this proposal. And finally I'd like to thank the Core Libraries Committee for ultimately decided on this proposal. I appreciate all of you! Lastly, should I submit a patch for this? I would be happy to, but the code involved is minimal and I don't mind if someone else wants to actually commit it. You can see the code and documentation that I would commit here: https://hackage.haskell.org/package/list-singleton-1.0.0.2/docs/Data-List-Si... On Sun, Sep 8, 2019, at 10:38 PM, Edward Kmett wrote:
https://groups.google.com/forum/#!forum/haskell-core-libraries should link to the CLC mailing list archive. As far as I can tell it should be public.
-Edward
On Sat, Sep 7, 2019 at 11:53 PM Helmut Schmidt
wrote: Am So., 8. Sept. 2019 um 05:59 Uhr schrieb Edward Kmett
: To grant some insight into what is going on behind closed doors. I figured I'd unpack a bit of it here.
Why is it necessary this gets discussed behind closed doors in the first place? Why can't we get more insight into the decision process of such a highly controversial proposal?
The current resolution is to treat this as step one in a longer maneuver.
*We'll be adding *singleton* to *Data.List*, immediately.*
The headache has really been the issue mentioned above wherein Data.List has historically been treated as an unqualified export that shouldn't clash with the Prelude in any way.
This is mostly a historical accident and doesn't really match up with the way any of the other "container" like modules are expected to be used. It has led to the somewhat messy state of dozens of other combinators in Data.List such as foldr having to be generalized by the Foldable/Traversable Proposal and other language warts starting to accumulate over time. It is disproportionately difficult to add things to Data.List, so we're going to fix that. -- We'd intended to fix that wart since GHC 7.10, but lacked a sufficient forcing function. Expanding the API of Data.List is acting as that forcing function.
*We are going to be switching the usage pattern for *Data.List* to expect a qualified or explicit import list like *Data.Text, Data.ByteString, Data.Set,* etc.*
This also helps allow for easier expansion of Data.List, which has been pretty stagnant other than a non-report-specified uncons slipping in stealthily in GHC 7.10.
It also helps ameliorate any long term concerns with this taking a name, as it is now something placed in a module where name collisions are okay, as usage is qualified or explicit. Meanwhile, Ryan GL Scott managed to accumulate enough data to show that breakage this one combinator would introduce was pretty minor after all, so we're going to go ahead with adding singleton before the rest of this happens.
To get *there*, we'll need a slightly longer timeline, and some support from GHC HQ to craft an appropriate warning. This will allow us to monomorphize the combinators in Data.List yielding a sane ending state that doesn't require a PhD in the History of Haskell to fully understand, and we'll be able to retire GHC.OldList once an appropriate 3-release policy compatible migration plan has been fully hammered out.
Normally, I'd wait until we had a full plan with all the migration issues posted rather than shooting off half-cocked like this, but I wanted to be clear about what was causing the communication delay.
-Edward
On Wed, Aug 28, 2019 at 12:57 PM Keith
wrote: For what it's worth, when starting out I found the disconnect between list sugar and list constructor/destructors extremely confusing. In retrospect it seems pretty silly, but I could not figure out how lists were consumed as (x : xs) but often produced with [x, x1, ...]. Mistakes like [x, xs] were common. When I finally realized that I could construct lists with the list constuctors, I started using them exclusively.
Simplcity and straightforwardness help understanding. It was much easier for me to understand a singleton list as (x : []) than [x]. Having to deal with '(singleton x)' (at the time not knowing the definition of 'singleton') would have been another layer of confusion.
I get that 'singleton' is library design, since in shows up in Map, Array, Set, etc. But for me trying to use lists, it would have only been useful if I defined it myself as a way to learn that constuctors are fuctions, and that 'singleton' means 'single'.
On August 23, 2019 7:56:41 AM UTC, Sven Panne
wrote: Am Do., 22. Aug. 2019 um 19:11 Uhr schrieb Kris Nuttycombe
: On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: > I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. [...] I think we can agree that we disagree here. ;-) My brain is too small to remember the names of myriads of trivial helpers, so I very much prefer general, orthogonal things. In our case: If we have a general, polymorphic function (often from a type class), just use that. If for some reason (rarely!) I want a more monomorphic function, I can just add a plain old type signature somewhere (no need for funky language extensions like type applications). This radically reduces the number of things one has to remember. In our case: Know type classes + know a way to make things more monomorphic.
> My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
This is exactly the opposite API design principle I have: Do not expose the monomorphic functions if they are already in a type class. You can easily reconstruct them as a library user via type signtures if this is really needed (still haven't seen many convincing examples of that), but you can' do it the other way round. Less things exposed, no generality/use cases lost => easier to remember.
The thing we can probably agree on: API design is hard and it's not an exact science, more a kind of art which is assessed in a subjective way... :-)
Keith -- Sent from my Android device with K-9 Mail. Please excuse my brevity. _______________________________________________ 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
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries

monomorphize the combinators in Data.List... retire GHC.OldList
Sounds great! Thanks for working on these improvements.
-- Dan Burton
On Sat, Sep 7, 2019 at 10:59 PM Edward Kmett
To grant some insight into what is going on behind closed doors. I figured I'd unpack a bit of it here.
The current resolution is to treat this as step one in a longer maneuver.
*We'll be adding *singleton* to *Data.List*, immediately.*
The headache has really been the issue mentioned above wherein Data.List has historically been treated as an unqualified export that shouldn't clash with the Prelude in any way.
This is mostly a historical accident and doesn't really match up with the way any of the other "container" like modules are expected to be used. It has led to the somewhat messy state of dozens of other combinators in Data.List such as foldr having to be generalized by the Foldable/Traversable Proposal and other language warts starting to accumulate over time. It is disproportionately difficult to add things to Data.List, so we're going to fix that. -- We'd intended to fix that wart since GHC 7.10, but lacked a sufficient forcing function. Expanding the API of Data.List is acting as that forcing function.
*We are going to be switching the usage pattern for *Data.List* to expect a qualified or explicit import list like *Data.Text, Data.ByteString, Data.Set,* etc.*
This also helps allow for easier expansion of Data.List, which has been pretty stagnant other than a non-report-specified uncons slipping in stealthily in GHC 7.10.
It also helps ameliorate any long term concerns with this taking a name, as it is now something placed in a module where name collisions are okay, as usage is qualified or explicit. Meanwhile, Ryan GL Scott managed to accumulate enough data to show that breakage this one combinator would introduce was pretty minor after all, so we're going to go ahead with adding singleton before the rest of this happens.
To get *there*, we'll need a slightly longer timeline, and some support from GHC HQ to craft an appropriate warning. This will allow us to monomorphize the combinators in Data.List yielding a sane ending state that doesn't require a PhD in the History of Haskell to fully understand, and we'll be able to retire GHC.OldList once an appropriate 3-release policy compatible migration plan has been fully hammered out.
Normally, I'd wait until we had a full plan with all the migration issues posted rather than shooting off half-cocked like this, but I wanted to be clear about what was causing the communication delay.
-Edward
On Wed, Aug 28, 2019 at 12:57 PM Keith
wrote: For what it's worth, when starting out I found the disconnect between list sugar and list constructor/destructors extremely confusing. In retrospect it seems pretty silly, but I could not figure out how lists were consumed as (x : xs) but often produced with [x, x1, ...]. Mistakes like [x, xs] were common. When I finally realized that I could construct lists with the list constuctors, I started using them exclusively.
Simplcity and straightforwardness help understanding. It was much easier for me to understand a singleton list as (x : []) than [x]. Having to deal with '(singleton x)' (at the time not knowing the definition of 'singleton') would have been another layer of confusion.
I get that 'singleton' is library design, since in shows up in Map, Array, Set, etc. But for me trying to use lists, it would have only been useful if I defined it myself as a way to learn that constuctors are fuctions, and that 'singleton' means 'single'.
On August 23, 2019 7:56:41 AM UTC, Sven Panne
wrote: Am Do., 22. Aug. 2019 um 19:11 Uhr schrieb Kris Nuttycombe < kris.nuttycombe@gmail.com>:
On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. [...]
I think we can agree that we disagree here. ;-) My brain is too small to remember the names of myriads of trivial helpers, so I very much prefer general, orthogonal things. In our case: If we have a general, polymorphic function (often from a type class), just use that. If for some reason (rarely!) I want a more monomorphic function, I can just add a plain old type signature somewhere (no need for funky language extensions like type applications). This radically reduces the number of things one has to remember. In our case: Know type classes + know a way to make things more monomorphic.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
This is exactly the opposite API design principle I have: Do not expose the monomorphic functions if they are already in a type class. You can easily reconstruct them as a library user via type signtures if this is really needed (still haven't seen many convincing examples of that), but you can' do it the other way round. Less things exposed, no generality/use cases lost => easier to remember.
The thing we can probably agree on: API design is hard and it's not an exact science, more a kind of art which is assessed in a subjective way... :-)
Keith -- Sent from my Android device with K-9 Mail. Please excuse my brevity. _______________________________________________ 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

Agreed this an even better outcome than I had hoped for!
On Sun, Sep 8, 2019 at 8:46 PM Dan Burton
monomorphize the combinators in Data.List... retire GHC.OldList
Sounds great! Thanks for working on these improvements.
-- Dan Burton
On Sat, Sep 7, 2019 at 10:59 PM Edward Kmett
wrote: To grant some insight into what is going on behind closed doors. I figured I'd unpack a bit of it here.
The current resolution is to treat this as step one in a longer maneuver.
*We'll be adding *singleton* to *Data.List*, immediately.*
The headache has really been the issue mentioned above wherein Data.List has historically been treated as an unqualified export that shouldn't clash with the Prelude in any way.
This is mostly a historical accident and doesn't really match up with the way any of the other "container" like modules are expected to be used. It has led to the somewhat messy state of dozens of other combinators in Data.List such as foldr having to be generalized by the Foldable/Traversable Proposal and other language warts starting to accumulate over time. It is disproportionately difficult to add things to Data.List, so we're going to fix that. -- We'd intended to fix that wart since GHC 7.10, but lacked a sufficient forcing function. Expanding the API of Data.List is acting as that forcing function.
*We are going to be switching the usage pattern for *Data.List* to expect a qualified or explicit import list like *Data.Text, Data.ByteString, Data.Set,* etc.*
This also helps allow for easier expansion of Data.List, which has been pretty stagnant other than a non-report-specified uncons slipping in stealthily in GHC 7.10.
It also helps ameliorate any long term concerns with this taking a name, as it is now something placed in a module where name collisions are okay, as usage is qualified or explicit. Meanwhile, Ryan GL Scott managed to accumulate enough data to show that breakage this one combinator would introduce was pretty minor after all, so we're going to go ahead with adding singleton before the rest of this happens.
To get *there*, we'll need a slightly longer timeline, and some support from GHC HQ to craft an appropriate warning. This will allow us to monomorphize the combinators in Data.List yielding a sane ending state that doesn't require a PhD in the History of Haskell to fully understand, and we'll be able to retire GHC.OldList once an appropriate 3-release policy compatible migration plan has been fully hammered out.
Normally, I'd wait until we had a full plan with all the migration issues posted rather than shooting off half-cocked like this, but I wanted to be clear about what was causing the communication delay.
-Edward
On Wed, Aug 28, 2019 at 12:57 PM Keith
wrote: For what it's worth, when starting out I found the disconnect between list sugar and list constructor/destructors extremely confusing. In retrospect it seems pretty silly, but I could not figure out how lists were consumed as (x : xs) but often produced with [x, x1, ...]. Mistakes like [x, xs] were common. When I finally realized that I could construct lists with the list constuctors, I started using them exclusively.
Simplcity and straightforwardness help understanding. It was much easier for me to understand a singleton list as (x : []) than [x]. Having to deal with '(singleton x)' (at the time not knowing the definition of 'singleton') would have been another layer of confusion.
I get that 'singleton' is library design, since in shows up in Map, Array, Set, etc. But for me trying to use lists, it would have only been useful if I defined it myself as a way to learn that constuctors are fuctions, and that 'singleton' means 'single'.
On August 23, 2019 7:56:41 AM UTC, Sven Panne
wrote: Am Do., 22. Aug. 2019 um 19:11 Uhr schrieb Kris Nuttycombe < kris.nuttycombe@gmail.com>:
On Thu, Aug 22, 2019 at 3:58 AM Sven Panne
wrote: I think there's a significant difference between "little helper" and "the monomorphic function that is used to implement `pure`" - with a slightly different framing, we might be able to come to an agreement that both the monomorphic an polymorphic versions of this function are useful in different contexts. [...]
I think we can agree that we disagree here. ;-) My brain is too small to remember the names of myriads of trivial helpers, so I very much prefer general, orthogonal things. In our case: If we have a general, polymorphic function (often from a type class), just use that. If for some reason (rarely!) I want a more monomorphic function, I can just add a plain old type signature somewhere (no need for funky language extensions like type applications). This radically reduces the number of things one has to remember. In our case: Know type classes + know a way to make things more monomorphic.
My guiding principle for API design is that one should always expose the fundamental building blocks as a low-level API, and then provide a smaller interface for the common use cases. Typeclass instances are no different - they are the general interface that allows us to invoke what is ultimately a monomorphic, low-level building block function in a polymorphic context.
This is exactly the opposite API design principle I have: Do not expose the monomorphic functions if they are already in a type class. You can easily reconstruct them as a library user via type signtures if this is really needed (still haven't seen many convincing examples of that), but you can' do it the other way round. Less things exposed, no generality/use cases lost => easier to remember.
The thing we can probably agree on: API design is hard and it's not an exact science, more a kind of art which is assessed in a subjective way... :-)
Keith -- Sent from my Android device with K-9 Mail. Please excuse my brevity. _______________________________________________ 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
_______________________________________________ Libraries mailing list Libraries@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries
participants (10)
-
Dan Burton
-
Edward Kmett
-
Elliot Cameron
-
Helmut Schmidt
-
Keith
-
Kris Nuttycombe
-
Sven Panne
-
Taylor Fausak
-
Tony Morris
-
Zemyla