Data.List (singleton)

446 views
Skip to first unread message

George Wilson

unread,
Aug 19, 2019, 9:33:38 PM8/19/19
to core-librari...@haskell.org
Fellow committee members,

As you know, there is a trac ticket and an ongoing discussion on
libraries@ regarding adding the following function to Data.List

singleton :: a -> [a]
singleton x = [x]

The discussion has continued for a week with nearly 50 replies. No
discussion period was given, but tensions are high and the discussion
is spilling into twitter. We should come to an official decision
sooner rather than later and put the issue to bed.

The maintainers of base are Edward and Ryan, but this is a
"controversial change" [1] because it requires changes to the Report
[2], which specifies the Data.List module.

The pages specifying our policies seem contradictory, which is a
problem of its own. [1] says the maintainer should make a decision,
probably after consulting with the rest of us. But [3] says we'll
decide by majority vote. Our actions have been more consistent with
[1] in my experience.

Edward or Ryan: Please come to a decision.

Current CLC votes:
+1 George
+1 Andrew
+1 Daniel
-1 Edward
-1 Carter
-1 Herbert

Sentiment is net positive among non-CLC libraries@ members.

Cheers,
George

[1] https://wiki.haskell.org/Library_submissions
[2] https://www.haskell.org/onlinereport/haskell2010/haskellch20.html#x28-22800020
[3] www.haskell.org/haskellwiki/Core_Libraries_Committee

Eric Mertens

unread,
Aug 19, 2019, 11:03:12 PM8/19/19
to George Wilson, core-librari...@haskell.org
As I mentioned on IRC, I’m +1 on the change. I prefer having it to using ‘pure’ when a list is what’s intended and not something more polymorphic as it improves code readability and helps type inference. I prefer the name singleton to (:[]), which is a common enough idiom to get the name robot monkey doesn’t have the elegance of a single identifier. I don’t care that the name singleton is longer when it comes to characters as its shorter when it comes to tokens. The name is obvious in what it does, so there’s nothing new for a reader to have to learn from reading haddocks.

I’m also in favor of making decisions; I don’t care what happens on Twitter.
> --
> You received this message because you are subscribed to the Google Groups "haskell-core-libraries" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to haskell-core-libr...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/haskell-core-libraries/CABzzMazKSwpuh6mp4eB_yL4QTrcRKvK6jR6cRgd%2BZhmuM3%2BSWg%40mail.gmail.com.

Herbert Valerio Riedel

unread,
Aug 20, 2019, 3:29:05 AM8/20/19
to George Wilson, core-librari...@haskell.org
Fellow committee members,

On 2019-08-20 at 11:33:01 +1000, George Wilson wrote:

[...]

> As you know, there is a trac ticket and an ongoing discussion on
> libraries@ regarding adding the following function to Data.List
>
> singleton :: a -> [a]
> singleton x = [x]
>
> The discussion has continued for a week with nearly 50 replies. No
> discussion period was given, but tensions are high and the discussion
> is spilling into twitter. We should come to an official decision
> sooner rather than later and put the issue to bed.

I don't like the concept of being pressued into a decision because
there's some Twitter mob out there trying to effect a certain
decision... if we decide the "wrong" way, that same Twitter mob will
certainly go away, right? ;-)

> The maintainers of base are Edward and Ryan, but this is a
> "controversial change" [1] because it requires changes to the Report
> [2], which specifies the Data.List module.

I feel like this should be emphasized more: This proposal is effectively
proposing to change the Haskell (Library) Report (and is also strongly
related to the overall language design of Haskell), and as such ought to
be justified by strong and compelling benefit.

And the proposal literally started out with the rationale of

> - `(: [])`: Subjectively ugly.
> - `(\x -> [x])`: Syntactically noisy.

If we start going down that road, you'll find that everyone has
different subjective perceptions. But since we're not designing a new
language, the best course of action IMO is to adhere to the design of
the language we have at our disposal; and in case of Haskell, the syntax
rules are designed in such a way that make (:[]) or (\x->[x]) an legit
construct.

IMO, Jon Fairbairn put it quite well,

,----
| > Idioms like (:[]) are not intuitive at all.
|
| Can you explain that? Once one knows that all infix operators
| can be used in sections (+1), (++"foo"), etc, that notation
| should be obvious, both in reading and writing. It’s much better
| to use ideas that are uniformly usable throughout the language
| and can be learned once than to have to learn numerous specific
| words.
`----

so IMO, `Data.List.singleton` doesn't really add much value and falls
short of some variant of the Fairbairn-threshold.

As you may know, I teach frequently students Haskell, and I frequently
do demonstration in GHCi, where stuff like (:[]) will easily slip in --
and it's a good thing, as then some student's curiosity about that
operator will be picked, et voila, I have a teachable moment to remind
everyone of the operator sections and variants such as (:"") or
((,)True), (True(,)), (:".exe") and so on...

David pointed out something similar:

,----
| Whilst taking the point, could I just pit out that, its not just about
| the form of the final program. One of the strengths and appeals of FP id
| the opportunity for program transformation via a useful repertoire of
| algebraic law, cf the work on Squiggol, and the numerous pearls by folk
| including Richard Bird et.al.. This work befits from having
| concisely-expressed rules that open the road to manipulation -
| long-winded identifiers suitable for large libraries are not necessarily
| ideal here.
|
| Going back to the original proposal, I'm not bothered, I would probably
| just ignore a singleton library in favour of :[]. I'm -1 on
| philosophical grounds.
|
| I'm used to teaching FP to undergrads and half the battle is encouraging
| people to think functionally, to make use of the underlying mathematics
| and computational model rather than transliterate Python or <insert your
| favourite 'bete noir'> into Haskell. That means thinking of building
| programs from functional fragments combined by suitable glue, and
| appreciating that data constructors can be used as functions Yes takes
| beginner's time to recognise some of the patterns, but when the light
| dawns, the transformation is rewarding. I've lost count of the number of
| jaws I've had to pick off the floor :)
`----

(Sideremark: what if somebody proposes to add Data.String.singleton on
the grounds they need a monomorphic singleton variant `:: Char ->
String` cause (:"") may be considered "subjectively ugly")

Also, we shouldn't add something to a Haskell Report module which I feel
won't see much use anyway for various reasons; see e.g. how Sven put it:

,----
| It is quite obvious to me why you don't find it much in code. You have
| lots of other ways to express the same thing:
|
| * You'll probably just use "[x]" if the argument already has a name.
|
| * If the argument doesn't have a name, you can give it one via
| "\x -> [x]" (which I consider "explicit", not "noisy") or perhaps
| via eta abstraction.
|
| * The code is intended to be polymorphic => "pure" is used.
|
| * Even if it's intended to be used monomorphic, there are often
| type signatures around to make "pure" monomorphic enough.
|
| This doesn't leave many sensible places. Perhaps as an argument for a
| function, with very few type signatures around? Not a very convincing
| use case IMHO.
|
| In a nutshell: Just like Herbert, I can't see the problem we're trying
| to solve. I would go even further: I would like to see a much more
| general Prelude/base library, not a more monomorphic one. Pages like
| https://haskell.fpcomplete.com/tutorial/synonyms cause quite a few
| "WTF?" moments caused by the (nowadays) useless synonyms...
`----

Moreover, in order to use it you'll have to `import Data.List` (assuming
you have a new enough `base`) at which point just reaching out for the
universal `(:[])` which is in principle available even without any names
imported, (i.e. `import Prelude ()`) will be what I argue most people
will just use (:[]) or (\x->[x]) in those rare occasions where you
really insist on using a list-specialised `::x->[x]`-type function.

So on the grounds that `Data.List.singleton` (by virtue of being a
redundant alias) doesn't add any technical benefit, lacks clear
consensus, seems inconvenient to use, is likely to end up being a
deadweight function only few people will use (if they even discover it),
it will likely not be mentioned (or at best be recommended against) by
FP teachers (like myself and David), it is a modification of the Haskell
Report which IMO doesn't carry its own weight (in fact, we should rather
try to remove redundancies in the Haskell Library Report than add even
more noise to it), I'm still strongly -1 on this.

`singleton` seems to be something more suited for one of the many
alternative preludes out there.

> Sentiment is net positive among non-CLC libraries@ members.

It's not a clear majority though, is it (it's currently somewhere
13-vs-16 on the libraries@ isn't it? i.e. flip two votes and we're
suddenly in a net-negative situation...)? As you pointed out, the
discussion got heated and is controversial; there certainly isn't any
clear consensus for this change.

And if there isn't a clear consensus that justifies and mandates a call
to action, shouldn't we rather leave the status quo as is than to push
some low-value purely cosmetic changes?

Edward Kmett

unread,
Aug 20, 2019, 8:15:09 AM8/20/19
to Herbert Valerio Riedel, George Wilson, core-librari...@haskell.org
I'm still personally somewhat against the proposed change, but I've basically come to the opinion that if Data.List was just like Data.Map and wasn't part of the report this might just rise the the level of being worth doing. 

But the problem is that Data.List isn't a module designed to be imported qualified like Data.Map. Many if not most uses of it aren't qualified, so people drawing analogies to the latter are trying to retroactively transform that module into something it has never been. This split-personality is part what led to the awful state that Data.List's foldr, etc. are in.

As it is? The amount of chatter on the mailing list does seem to indicate a clear lack of consensus in the large. In the absence of such a consensus I tend to give a lot of weight to the status quo.

This ultimately leaves me saying little that Herbert hasn't said better above.

To grant this request, I'd want to drastically overhaul all of Data.List to make it clear that it should be imported qualified and to make sure that the new report was phrased accordingly. While that is a hell of a lot of bikeshed to repaint, there is slowly mounting pressure to do something like this that you can see when you consider that list-monomorphic versions of foldr, foldl, etc. which have to exist as separate top level definitions for {-# RULES #-} firing reasons, should live somewhere. Right now they are off in GHC.OldList.

The real problem is whether or not there is an actual will to make that sort of thing happen. I sure don't have it, because I don't necessarily think it is a good idea. I mention it, mostly because is a point in the design space that would readily admit a monomorphic 'singleton' combinator with a pretty clear conscience.

Mind you, George cracked a joke on Twitter the other day about base 5 and a whole bunch of people started having heart palpitations. Something like this larger refactoring might be the sort of thing that could take place as part of a larger, better motivated move to such a major version overhaul.

Now, that said, I don't want to quite so gratuitously move the goal posts from the original proposal. Even I can see that "hey i want to add this 'singleton' combinator over here" does not directly imply "hey we should break the entire ecosystem."

-Edward

P.S. It is just after 5am here, and I'm clawing my way to bed because I can't keep my eyes open. Posting this before proof-reading to keep the discussion going. Apologies for any incoherence.

--
You received this message because you are subscribed to the Google Groups "haskell-core-libraries" group.
To unsubscribe from this group and stop receiving emails from it, send an email to haskell-core-libr...@googlegroups.com.

George Wilson

unread,
Aug 21, 2019, 9:58:22 PM8/21/19
to Edward Kmett, Herbert Valerio Riedel, core-librari...@haskell.org
I find myself persuaded from weak +1 to -1, by Herbert and Edward's
arguments.

Edward Kmett

unread,
Aug 22, 2019, 4:31:44 AM8/22/19
to George Wilson, Herbert Valerio Riedel, core-librari...@haskell.org
I think I’m more a -1 until we can overhaul Data.List to expect it to be imported qualified in a report than a -1 forever.

I realize that Herbert and I may disagree on that part.

Sent from my iPhone

chessai .

unread,
Aug 27, 2019, 10:52:33 PM8/27/19
to Edward Kmett, George Wilson, Herbert Valerio Riedel, core-librari...@haskell.org
Ryan, have you had a chance to think about this?

Thanks

chessai .

unread,
Aug 27, 2019, 11:14:06 PM8/27/19
to Edward Kmett, George Wilson, Herbert Valerio Riedel, core-librari...@haskell.org
BTW, im not quite -1, but i think my medium-strengthed +1 has been reduced to a weak +1, also due to Edward/Herbert's arguments 

Carter Schonwald

unread,
Aug 28, 2019, 12:51:19 AM8/28/19
to chessai ., Edward Kmett, George Wilson, Herbert Valerio Riedel, core-librari...@haskell.org
I’m -1 atm because I’m pretty sure that adding it will break some code out there.  Been traveling so not situated to do a hackage scale Grep etc. but this seems like a “consistency for the sake of imagined consistency ” where there’s genuinely no change in expressivity 

-Carter

Edward Kmett

unread,
Sep 4, 2019, 4:47:36 PM9/4/19
to Ryan Scott, George Wilson, chessai ., Herbert Valerio Riedel, core-librari...@haskell.org, Carter Schonwald
Ryan's quantitative analysis makes me willing to flip to a very weak +1.

I roughly estimate that fewer libraries will break than the number of people that would be made happy by the change, even I'm not among their number.

As base "maintainer", I think I'm willing to call it in favor of actually making the change.

-Edward

On Wed, Sep 4, 2019 at 10:28 AM Ryan Scott <ryan.g...@gmail.com> wrote:
My apologies for chiming on this rather late (I never received the core-libraries-committee@ email for some reason).

As far as the technical merits of the singleton function go, I'm quite ambivalent. I probably wouldn't use this combinator in my own code, but it is clear from the discussion that there are several folks who would be quite eager to use it in their code. In these sorts of situations, I usually fall on the side of the people who want the combinator, provided that the costs of maintaining it are low.

In this case, however, there is concern that adding singleton would incur some non-trivial costs. I've been reluctant to chime in before since I never had a good sense of how to quantify these costs, so here is my attempt to do so. Two notable costs that come to mind are:
  1. The cost of changing Data.List, which is specified by the Haskell Report
  2. The cost of exposing a function named singleton (which is used by many other libraries) from Data.List, which is usually imported unqualified
As far as (1) goes, it is worth noting that the base library's version of Data.List already extends the Haskell Report's specification of Data.List, since it includes functions such as uncons, dropWhileEnd, isSubsequenceOf, and sortOn, which are not mentioned in the Report. Presumably, we'll have to deal with all of these functions if the Haskell Report is ever updated, so we wouldn't be breaking new ground by adding more things to Data.List. The specification for singleton is about as simple as you can get, so I don't forsee any issues with specifying it in a future Report.

In short, I don't think the costs associated with (1) are enough to reject this proposal on their own.

Point (2) is more interesting. There are various libraries with modules that define a function named singleton, usually with the expectation that these modules be imported qualified. However, the need for qualified imports is usually because of other functions that share names in common with things from base, such as insert. Up to this point, singleton has not been these contentious names, so I could imagine that there would be code that imports a singleton function directly, perhaps even alongside an import of Data.List.

I was curious to know exactly how much code does something like this (and would therefore break if singleton were added to Data.List), so I peformed an informal experiment. I compiled GHC 8.6.5, but with singleton added to Data.List, and built a large variety of libraries from Hackage to see what would break. When I was done, my ~/.cabal/store directory for this version of GHC had 523 entries, which provides a loose upper bound on the number of libraries that successfully built (there are some duplicate entries). If you're curious, you can view these store entries at [1].

Now for the interesting part: how many libraries did not build? There three libraries that failed to build (that would have otherwise succeeded with a vanilla GHC 8.6.5):
  • blank-canvas-0.7
  • ghc-lib-parser-8.8.0.20190723
  • pandoc-2.7.3
This surprised me, since I would have anticipated the breakage to be much more significant than this. Of course, this experiment is not exhaustive—there are many other libraries out there, and there is also lots of code that is not on Hackage. But the amount of breakage from this subset of ~500 libraries or so was quite small indeed, especially when contrasted with things like the AMP, FTP, or SMP, which broke a much higher percentage of code.

While I certainly see Edward's point about the potential perils of Data.List being imported unqualified everywhere, this experiment changed my mind about how perilous it would actually be in practice. In light of this, I can't say that I find point (2) to be sufficient grounds for rejecting this proposal either.

-----

Where does that leave me? I don't see a particularly compelling reason to reject the proposal outright—I was originally leaning towards -1 due to my preconceived notions about point (2) above, but I have since changed my mind on that. Moreover, I try not to let my personal feelings about how useful a function would be in the sort of code I write dictate my vote on matters like these, since I recognize that Haskell is a diverse language with many different ways of writing code. In light of this, I'm +1 (or weak +1, if the vote is close enough that adjectives matter). That being said, my vote is not set in stone, and I'd welcome any feedback on my analyses above.

On Wed, Sep 4, 2019 at 8:08 AM George Wilson <geo...@wils.online> wrote:

Carter Schonwald

unread,
Sep 4, 2019, 5:13:51 PM9/4/19
to Edward Kmett, Ryan Scott, George Wilson, chessai ., Herbert Valerio Riedel, core-librari...@haskell.org
I guess I’m in the same sort of +/-0 stance myself if the statistics on impact bear out as Ryan indicates. 

Better question: if included , should it be a pattern synonym?

-Carter

Edward Kmett

unread,
Sep 4, 2019, 5:25:03 PM9/4/19
to Carter Schonwald, Ryan Scott, George Wilson, chessai ., Herbert Valerio Riedel, core-librari...@haskell.org
I'm inclined to just offer the combinator. The idea of stuffing a pattern synonym in a report specified module makes me uncomfortable. It'd be that much harder to ever standardize into the report as the report predates them and it'd be a large addition. With just a combinator, it is a very small addition to the report.

-Edward

Carter Schonwald

unread,
Sep 4, 2019, 5:26:06 PM9/4/19
to Edward Kmett, Ryan Scott, George Wilson, chessai ., Herbert Valerio Riedel, core-librari...@haskell.org
Yeah. Can of worms.  Agreed. 

-Carter

Eric Mertens

unread,
Sep 4, 2019, 5:27:18 PM9/4/19
to Edward Kmett, Carter Schonwald, Ryan Scott, George Wilson, chessai ., Herbert Valerio Riedel, core-librari...@haskell.org


On Sep 4, 2019, at 2:24 PM, Edward Kmett <ekm...@gmail.com> wrote:

I'm inclined to just offer the combinator. The idea of stuffing a pattern synonym in a report specified module makes me uncomfortable. It'd be that much harder to ever standardize into the report as the report predates them and it'd be a large addition. With just a combinator, it is a very small addition to the report.

-Edward

On Wed, Sep 4, 2019 at 2:13 PM Carter Schonwald <carter.s...@gmail.com> wrote:
I guess I’m in the same sort of +/-0 stance myself if the statistics on impact bear out as Ryan indicates. 

Better question: if included , should it be a pattern synonym?

-Carter

The other reason to stick with just the combinator is that it follows the pattern of the other modules that export `singleton` (lowercased) and as a pattern `[x]` is already pretty great. While as an expression we’re likely tow ant to use singleton unapplied, this doesn’t happen with patterns.

George Wilson

unread,
Sep 5, 2019, 11:46:46 PM9/5/19
to Eric Mertens, Edward Kmett, Carter Schonwald, Ryan Scott, chessai ., Herbert Valerio Riedel, core-librari...@haskell.org
Great, sounds like both base maintainers are in agreement. Can one of
you please report the result back to the libraries list?

Herbert Valerio Riedel

unread,
Sep 6, 2019, 7:24:54 AM9/6/19
to Ryan Scott, George Wilson, chessai ., Edward Kmett, core-librari...@haskell.org, Carter Schonwald
> Point (2) is more interesting. There are various libraries with modules that define a function named singleton, usually with the expectation that these modules be imported qualified. However, the need for qualified imports is usually because of other functions that share names in common with things from base, such as insert. Up to this point, singleton has not been these contentious names, so I could imagine that there would be code that imports a singleton function directly, perhaps even alongside an import of Data.List.

What also needs to be taken into account though is that this would
steal a name `singleton` from the `Prelude`/FTP namespace; even though
it could be conceivable at some point to end up with a `singleton ::
.... => x -> a` living somewhere; and if that happens we'd end up
either having to polymorphisie `Data.List.singleton` (which would
render the original proposal kinda moot) or cause a hard nameclash
between Prelude and Data.List

So I'm still a strong -1 here

Carter Schonwald

unread,
Sep 6, 2019, 7:27:04 AM9/6/19
to Herbert Valerio Riedel, Ryan Scott, George Wilson, chessai ., Edward Kmett, core-librari...@haskell.org
Hrmmmm... this is a valid point.

-Carter

Herbert Valerio Riedel

unread,
Sep 6, 2019, 7:28:09 AM9/6/19
to Ryan Scott, George Wilson, chessai ., Edward Kmett, core-librari...@haskell.org, Carter Schonwald
For the record, here's the potential polymorphic incarnation I showed
in the original libraries discussion:

> > There is a concept here: create a container containing exactly one value. As Tikhon indicates, this is a different concept from pure.
>
> Fwiw, if you actually want a possibly meaningful/lawful reification of
> the very specific "create any container containing exactly one item"
> concept then an obvious approach would be to base it on the existing
> (IMO under-appreciated) 'IsList' abstraction; in other words basically
> something like
>
> singleton :: IsList l => Item l -> l
> singleton = fromListN 1 . (:[])
>
> which could either be a method of `IsList` (with the default impl
> above and an obvious lawful relationship to `fromList`/`toList`) or
> just be a top-level binding exported from "GHC.List" and/or "GHC.Exts"
> (which aren't governed by the Haskell Library Report and thus have a
> lower barrier to entry).

Ryan Scott

unread,
Sep 6, 2019, 10:00:27 AM9/6/19
to Herbert Valerio Riedel, George Wilson, chessai ., Edward Kmett, core-librari...@haskell.org, Carter Schonwald
I can certainly understand being reluctant to steal the name "singleton" away from future designs, especially in light of the fact that Data.List is usually imported unqualified. Would this be an issue if singleton :: a -> [a] were named something else? I don't have an alternative name in mind (and indeed, I don't think coming up with such a name is our task at present), but that might avoid these sorts of issues.

Ryan

Herbert Valerio Riedel

unread,
Sep 6, 2019, 7:21:39 PM9/6/19
to Ryan Scott, George Wilson, chessai ., Edward Kmett, core-librari...@haskell.org, Carter Schonwald
On Fri, Sep 6, 2019 at 4:00 PM Ryan Scott <ryan.g...@gmail.com> wrote:
> I can certainly understand being reluctant to steal the name "singleton" away from future designs, especially in light of the fact that Data.List is usually imported unqualified. Would this be an issue if singleton :: a -> [a] were named something else? I don't have an alternative name in mind (and indeed, I don't think coming up with such a name is our task at present), but that might avoid these sorts of issues.

Well, I do consider it definitely our task to consider the
ramifications, and not make life for future-selves harder by making
poor choices now... ;-)

You could of course decide to intentionally create a language wart by
inventing new names; this is the unfortunate situation we ended up
with `fmap` and `map`, where every semester I keep getting asked by
Haskell newcomers to explain the existence of two different terms
`fmap` and `map` for the same concept, and justify it by historic
reasons and that the `Data.List` module is home to list-specialised
functions...only to have to concede half a minute later that the
latter promise has been broken since GHC 7.10.3, when `Data.List`
became polymorphic for many of its operations, as FTP threw `base`
into the idiom that the global namespace (of unqualified imports)
ought to have polymorphic versions, while qualified imports shall
provide type-specialised verbs (except for Data.List, which as we've
pointed out isn't intended to be imported qualified).

And then quite a few of the students end up using questionable
libraries such as "classy-preludes" mostly to have a more unified
(++)==(<>) or fmap==map story in their default scope; and I can't
really blame them.

And since personally I'd love to see `fmap` be renamed (or at least
aliased) to `map` myself, I'm definitely not a supporter of
intentionally creating yet another such wart (which might only make it
even harder to justify unifying fmap and map et al. the more such
divergences exist) by inventing a new name for the polymorphic version
of a function, especially since Data.List.singleton doesn't exist yet
and so we can avoid ending up in that situation by virtue of having
20/20 hindsight with the fmap/map wart.

Edward Kmett

unread,
Sep 6, 2019, 9:59:11 PM9/6/19
to Herbert Valerio Riedel, Ryan Scott, George Wilson, chessai ., core-librari...@haskell.org, Carter Schonwald
I think long term, I'd still like to switch the dominant idiom for Data.List usage to become one of qualified and/or explicit import lists. 

That part isn't likely to happen for a number of releases, as placing monomorphic folds and list combinators in there (or just outright removing them) as part of the transition is a much bigger pain point (and one that probably requires a round of warning support in GHC that GHC currently doesn't know how to offer.)

That caveat doesn't apply to the existence of a monomorphic singleton combinator, especially if we view it as a step towards making Data.List a qualified container-like import.

As it stands the non-report-based existence of uncons should have raised basically all these same concerns. Yet it stealthed through the process undetected and uncommented in GHC 7.10.

The end state there strikes me as better than the status quo, because then Data.List can be thought of as fitting the idiomatic usage qualified container library pattern of NonEmpty, Map, Set, Text, ByteString, and we'd be able to drop the polymorphic re-export of foldr, etc. in there that are frankly a laughable wart.

A sketch of my proposed roadmap is to

1.) introduce singleton into Data.List in the next major GHC release.

2.) work with GHC HQ to see if we can't get some warning of unqualified imports of the Foldable re-exports from Data.List,blocking further changes to Data.List until we get a plan that works.

3.) monomorphize the remaining combinators in Data.List after a suitable 1-2 GHC release warning period, switching to the versions currently buried in GHC.OldList. (The three-release policy doesn't bite this at all, as using qualified imports would work across both monomorphic and polymorphic versions of those combinators.)

4.) Retire GHC.OldList after a suitable migration period to comply with the 3-release policy.

In the final state Data.List looks and feels like any other monomorphic container module, and doesn't feel any different from working with Data.Text or Data.ByteString except for the fact that some combinators that work with lists remain exported from the Prelude. After that any minor additions to Data.List can be just that, minor additions, no more special than adding something to Data.Tuple or Data.Either.

The end result cleans up a major outstanding wart from the FTP, reduces how "special" Data.List is in usage, making it a bit more newbie friendly, grants the folks who are looking for it a monomorphic combinator, which is clearly tucked away and doesn't wind up with a Prelude-namespace affecting situation where an important name is tied up long term.

-Edward

Herbert Valerio Riedel

unread,
Sep 7, 2019, 3:40:02 AM9/7/19
to Edward Kmett, Ryan Scott, George Wilson, chessai ., core-librari...@haskell.org, Carter Schonwald
On Sat, Sep 7, 2019 at 3:59 AM Edward Kmett <ekm...@gmail.com> wrote:
>
> I think long term, I'd still like to switch the dominant idiom for Data.List usage to become one of qualified and/or explicit import lists.

That's something I do support regardless of whether
`Data.List.singleton` is added; but I strongly advocate to let's have
Data.List become a module that is included asap and not something that
drags on for 3-5 years but is rather achieved within a ~2y time-frame.
It's already gonna be a huge uphill battle and better get it done
sooner rather than later to reduce the surface in the time-dimension
for dissent to build up and social media mobs forming...

And it's also quite relevant to get the details down for an upcoming
Haskell Library Report which should rather aim for the end-result than
encode the transitional messy FTP state Data.List is currently in;
Just as a reminder, see

http://hackage.haskell.org/package/haskell2020

as a sketch for what H2020 (or whatever it'd gonna be called) could be.

> As it stands the non-report-based existence of uncons should have raised basically all these same concerns. Yet it stealthed through the process undetected and uncommented in GHC 7.10.

Yes, uncons was also a questionable addition; but the difference is
that `uncons` has actual value as it gives you a concise name for
something that would otherwise be cumbersome to express in a points
free style. This pushes singleton's value way below `uncons` into the
area of not being defendable at all in terms of Fairbairn thresholds
et al; compare

singleton = (:[])

to

uncons = \x -> case x of { [] -> Nothing; x:xs -> Just (x,xs) }

So to me the comparison with uncons while superficially similar ends
up being unfair when it comes to its objective merit, as the `uncons`
one at least has an objectively measurable benefit, while `singleton`
objectively doesn't, and in fact is rather a pessimification in terms
of conciseness and idiomatism. Also we'd create a precedent for
low-value additions which lowers the bar even more for redundant
feel-good-additions to the library report.

Also note that there's no `unsnoc` operation in Data.List for obvious
reasons while most other APIs that have a `uncons` operation also have
a `unsnoc` operation. So it's not that we'd want to add verbs to
Data.List just because of subjective feels; it also has to be
justifiable on measurable objective grounds.

Also note that I did not include `uncons` in

http://hackage.haskell.org/package/haskell2020

either... yet... ;-)

> The end state there strikes me as better than the status quo, because then Data.List can be thought of as fitting the idiomatic usage qualified container library pattern of NonEmpty, Map, Set, Text, ByteString, and we'd be able to drop the polymorphic re-export of foldr, etc. in there that are frankly a laughable wart.

No disagreement here; and I really like to reach that more principled
end-state asap (especially if singleton is going to be added for
real). Do we need to invoke a formal decision process or does your
statement already count as an executive order? ;-)

Edward Kmett

unread,
Sep 7, 2019, 10:00:05 AM9/7/19
to Herbert Valerio Riedel, Ryan Scott, George Wilson, chessai ., core-librari...@haskell.org, Carter Schonwald
On Sat, Sep 7, 2019 at 12:39 AM Herbert Valerio Riedel <hvri...@gmail.com> wrote:
On Sat, Sep 7, 2019 at 3:59 AM Edward Kmett <ekm...@gmail.com> wrote:
>
> I think long term, I'd still like to switch the dominant idiom for Data.List usage to become one of qualified and/or explicit import lists.

That's something I do support regardless of whether
`Data.List.singleton` is added; but I strongly advocate  to let's have
Data.List become a module that is included asap and not something that
drags on for 3-5 years but is rather achieved within a ~2y time-frame.
It's already gonna be a huge uphill battle and better get it done
sooner rather than later to reduce the surface in the time-dimension
for dissent to build up and social media mobs forming...

Lancing that boil is one reason why I'm willing to roll over on singleton, especially given Ryan's data showing it isn't that bad in practice.

I think we can get there in a reasonably short timeframe, if we can get warnings for unqualified use of Data.List.foldr, etc. in place in GHC. That will be the thing that determines the overall timeline more than anything.

We have a couple of directions we could take the warning.

A.) -Wmonomorphic-data-list should warn if null, length, foldr, foldl, foldl', foldl1, foldr, foldr1, concat, concatMap, and, any, or, all, sum, product, maximum, minimum, elem, notElem, find, maximumBy, minimumBy, mapAccumL, mapAccumR (basically anything with a Foldable or Traversable constraint mentioned in Data.List) are used in a module where they are simultaneously imported at the same name from Data.List (which currently re-exports their polymorphic forms) and from another source.

Basically in this world it is okay to import Data.List unqualified if you don't use any of the names it (will) clash with Prelude on. 

This would require some ability to taint an export with its provenance, or something more peculiar to this effort to track a flag for where these symbols originally came from when they are in scope. 

Pros: it tracks exactly what code will break now. 
Cons: it isn't very robust against future additions to Data.List breaking code for unqualified users.

B.) we could just write a simple warning that complains if you don't either use explicit import lists or qualify your import of Data.List.

Pros: It would be a much simpler flag to add to GHC, mucking with almost no internals at all. It also would be something potentially useful in the long term, even after the transition, as a sanity check that future additions to Data.List should always be safe.
Cons: It does complain a bit too loudly about current usage, even when you don't use any of the functionality that will change.

I'd probably be happy enough with either warning version. The former might build us some better tools for future library efforts, the latter is likely a lot less effort.
Once Data.List has a qualified usage pattern, adding unsnoc, etc as part of a broader API like the one offered by Data.List.NonEmpty is not something I'd be against. 

Also note that I did not include `uncons` in

http://hackage.haskell.org/package/haskell2020

either... yet... ;-)

> The end state there strikes me as better than the status quo, because then Data.List can be thought of as fitting the idiomatic usage qualified container library pattern of NonEmpty, Map, Set, Text, ByteString, and we'd be able to drop the polymorphic re-export of foldr, etc. in there that are frankly a laughable wart.

No disagreement here; and I really like to reach that more principled
end-state asap (especially if singleton is going to be added for
real). Do we need to invoke a formal decision process or does your
statement already count as an executive order?  ;-)

We've wrangled about this for quite some time. We have a pretty good idea of where everybody stands.

I'm willing to just count this as the maintainer decision for chosen direction lest we waste everybody's time even further, and to allow us to figure out how to proceed with execution.

-Edward

Ryan Scott

unread,
Sep 7, 2019, 6:30:35 PM9/7/19
to Edward Kmett, Herbert Valerio Riedel, George Wilson, chessai ., core-librari...@haskell.org, Carter Schonwald
I agree with everything that Edward says about the future direction of Data.List. I can't imagine that such a migration to qualified imports should spark too much controversy (at least, not as much as the singleton proposal).

What is the best way to advertise this plan? Should a ticket be filed against GHC? Should an announcement be made on the libraries mailing list? A combination of the two? Something else?

Ryan

Edward Kmett

unread,
Sep 8, 2019, 2:05:03 AM9/8/19
to Ryan Scott, Herbert Valerio Riedel, George Wilson, chessai ., core-librari...@haskell.org, Carter Schonwald
I took the liberty of giving a general outline of the current plan on the original thread. 

Folks there were, fairly rightly IMHO, getting a bit agitated about the delay in getting what they perceived as a simple a yes/no answer here.

I suspect at the least we should update the core libraries timeline page and put together an appropriate timeline for this.

Once we have all our ducks in a row, then we should make a broader announcement.

-Edward
Reply all
Reply to author
Forward
0 new messages