But you can already write “one-off scripts with no .cabal file”, right?
Huh, yeah, I guess you’re right. I’m pretty sure I had seen that before, but didn’t remember it. That’s definitely better than not having the option. It’s still not particularly discoverable, so it’s pretty bad for beginners: they’d need to add some special boilerplate just to have access to basic types.
But, to @tomjaguarpaw’s point, we could address that by using the same mechanism to provide more packages by default rather than absolutely needing to merge everything into base
.
While I think of it: given how special base
is to GHC, and that it’s non-upgradeable, put me down for being in favour of as small a base
as possible, and better user education around common libraries so that depending on common packages like text
and containers
doesn’t seem scary to them.
I wish we had vector in base, it is more commonplace and better than Array in base yet Array still has the special status. Vector in base with appropriate special treatment would be great. (The only reason I would use OverloadedLists extension is just for vector, same as OverloadedString for text)
This is getting off topic - my main concern is with the base
library. Project customization comes in at a later step.
What I want to know is: which direction is most favoured by the community in terms of the base
API? Should we invest the effort into merging base
and text
? If we do, I’d want to do more than just a glorified re-export. I want to see Read/Show
using Text. I want fromString
to become fromText
, and I’d even go as far as making Text
the default type of string literals, with my magic wand. This is the sense I’ve been getting from this thread: String
was a mistake, and we should invest in fixing it, even if it means – heaven forbid! – straying yet further from the ancient Report.
That’s fair, though I think what has come to light is that everyone has good diverging ideas on things that should be included by default in base, and that to fulfill that using more packages by default seems like the right solution (at least I and @tomjaguarpaw lean towards it), more so than progression in base
.
(Except for text
, which would have far reaching consequences when merged into base and preferred over String
which seems to generally agreed upon here)
Could a mod could split the above “idea” comment over to its own post? A separate discussion does seem better to discuss that concrete proposal, and whether it should be acted upon.
I prefer to think of String
(and for that matter, the ol’ monomorphism restriction) more as temporary “scaffolding” - there were good reasons in the past for having them in order to get Haskell "up and running". But now each have served their purpose, so it’s probably time to remove them.
Haskell 2010 retired the monomorphism restriction (n+k)
patterns; perhaps e.g. Haskell 2024 can just retire String
in favour of Text
- as you eluded to, that one change by itself would be quite substantial:
-
I want to see
Read
/Show
usingText
Agreed.
-
I want
fromString
to becomefromText
…along with replacements for
getStr
, theputStr
s (and yes; even the likes oferror
- no “scope creep” please!) -
[…] I’d even go as far as making
Text
the default type of string literalsDefinitely YES! That could make the first step in switching to Text as simple as:
sed 's/\<String\>/Text/g'
…as opposed to trying to prefix many and varied type signatures with
Str
(likeNum
)IsString
.
So much for memory! I thought H2010 also dropped the MR - perhaps I was looking at a draft version? ;-/
Honestly, I think something like this may be a way forward, for one critical reason - it sidesteps the issue of asking the conflicting questions of whether things should be added (base
is too small) or things should be removed (base
is too big), in favor of a way that acknowledges both.
Breaking base
up into smaller components and then using flags (or some other method) to control and conditionally prune or include components would allow for a chosen set of default components to form the canonical base
, while also allowing for default components to be pruned out, and optional components to be included, making it easier to experiment with changes and for base to be extended.
Then base
can be published much as-is, plus a minimal base-slim
and a maximal base-all
, and anything more specific than this is honestly probably worth doing yourself.
This is exactly why I mentioned splitting base
above (and later on, in private conversation with @Kleidukos) as a potential solution to these problems. I’m really hopeful that it would allow something like this to be achieved.
`PartialEq` & `PartialOrd`, superclasses of `Eq` & `Ord`.
At that point we might as well have TotalEq
& TotalOrd
, superclasses of Eq
& Ord
.
Coming from Rust, I miss the From
and TryFrom
traits.
The witch
package provides a direct equivalent, so I usually start from Relude and add this on top of it.
Coupled with ViewPatterns it lets you write polymorphic code in such a convenient way:
doThingWithTimestamp :: From t UTCTime => t -> SomeRecord
doThingWithTimestamp (into -> utcTime) = _
I wish we had a standardized way to perform conversions like the Rust ecosystem has.
I personally dislike these sorts of typeclasses; my experience is that an instance basically just means that there exists at least one function from A
to B
, with no real assertion about its properties, and that’s a really weak condition. It’s particularly bad between string types in a team environment, where someone sets up a ToText
class meaning “a lossless conversion exists” and then people add in instances which pretty-print or render in some other way. IMHO, the “what type is actually being passed in here?” experience is real, frequent, and often unpleasant.
If you write it out without the typeclass, it’s the same as doThingWithTimestamp :: (t -> UTCTime) -> t -> SomeRecord
, so I usually cut to the chase and write UTCTime -> SomeRecord
instead.
Changing topic:
I’d also like to see the symbolic functor combinators defined in GHC.Generics
moved into Data.Functor.*
, and become the canonical names. Then Data.Functor.Sum.Sum
, Data.Functor.Product.Product
, and Data.Functor.Compose.Compose
can all be deprecated and removed.
I do not have any gripes with base
.
I sometimes have to look up what version of base
is a boot library of what version of GHC - it would be nice if that table was part of the Haddock documentation of base
. (EDIT: I usually refer to either version history · Wiki · Glasgow Haskell Compiler / GHC · GitLab or https://wiki.haskell.org/Base_package.)
The Stack project chooses to use {-# LANGUAGE NoImplicitPrelude #-}
and import RIO
from rio
, but I don’t view that as a deep criticism of Prelude
. That said, the README for rio, explaining its motivation, characterises partial functions and lazy I/O as ‘gotchas’ to be removed from a useful prelude.
This FP Complete tutorial on string types advises that using type String = [Char]
to represent textual data should be avoided ‘whenever possible’, replacing instead with (strict) Text
- but observes that String
is the only string-like type defined in base
.
You can get exactly that table with ghcup list
!
That’s amazing, I never knew that! I always went to some obscure page on the GitLab. Thanks for the tip, though I think putting it in the documentation is also a good idea; it would just require upkeep
I think it is somewhere in the documentation too (on the GHC Wiki in the GitLab, perhaps?), but I can never remember where, and using ghcup list
is just so much easier that I never bother.