Informal discussion about the progression of `base`

Random is fine IMO. In haskell that would be exactly like you wish it to be:

import System.Random (randomRIO)

main = do
  x <- randomRIO (69, 420 :: Int)
  print $ x * 2
1 Like

You can actually do this — just run cabal repl -b random to launch GHCi with random accessible. I’ll admit this isn’t exactly well-advertised, though, and the friction is definitely an issue (hence why I suggested random earlier as one of the more important packages which could be merged into base).

I think this is largely the fault of the docs, honestly — reorganising them a bit would do wonders. (As a matter of fact, we were complaining about this just the other day over on the FP Discord server.) Random numbers are naturally trickier in Haskell than in Python, since we want to avoid mutable state, and the API itself probably makes the best tradeoffs possible given this constraint.

2 Likes

The problem is that the authors would have to go and update projects to keep in sync.
While this is arguably a benign change and the result would worth it, it is an unwanted* chore.

Add chants of “Text? What is it good for?” and “Don’t optimize before you measure!” and… here goes nothing.

*It would be done already if it was a wanted one.

I actually knew this! I think the fact that I forgot it was possible is indicative of the problem! I’m glad you agree the friction is an issue - launching these one off scripts should require no thought and no friction. Haskell is a high level, garbage collected language with a REPL, and imo as such should support high level scripting capabilities in a similar niche to python without having to make use of package managers or build tools.

I think the naming isn’t ideal either - to take the example wiz gave, I think randomRIO is a much worse name than python’s equivalents random.range and random.uniform.

I disagree with the premise. In most common use cases, people making use of randomness are fine with impurity and expect it. They understand the nature of randomness. They usually aren’t concerned with reproducibility - if they specifically need that feature, they’ll deliberately seek it out. The API should simply make use of mutable state - that’s why I advocated a default of IO. I think it’s really worth interrogating whether we’re using functional purity out of ideology or just out of habit, or because it’s actually the best tool for the job. In my opinion it’s not the correct tradeoff here.

2 Likes

I’m also in the boat of having smaller packages, but a better story for using them all together by default.

Something like having them all by default in build-depends sounds like a simple yet great idea

4 Likes

And since we’re doing our xmas wishing too, for me it’d be Fix in base. It seems like a widely useful concept that gets redefined over and over across libraries, or implies a dependency in data-fix.

2 Likes

We definitely have a lot of friction that prevents many of our nice features from being used as much as they might. cabal -b/--build-depends is one such.

1 Like

Almost? If the packages were also automatically available to runhaskell/ghci/etc—so that we could always depend on them and use them for one-off scripts with no .cabal file—then it would behave the way I’d want.

At that point, though, it seems like we end up with a standard library that happens to be split over multiple packages under the hood. What’s the advantage there? Backwards compatibility? More flexibility around releases and versioning? (Honestly, I could see just those two being enough as long as we can make it work seamlessly in all our tooling.)

1 Like

I want to rip out lazy IO out of base and possibly replace it with proper streaming.

This might be a pipe (lol) dream, but anyway.

6 Likes

More like a “pipes” dream :wink:

Streaming is a tricky thing because there are so many different designs floating around for a core streaming abstraction, but it also seems critical because streams are such a foundational interface type. Lots of APIs naturally want to be streaming, but today that means needing to buy into one specific streaming library at the expense of the others. Not ideal if you’re trying to write a general-purpose library and minimize your dependencies.

2 Likes

The problem is that the [packages’] authors would have to go and update [their] projects to keep in sync.

That is true, but at least they would have a ready-made patch - it would be an exercise in “lessening friction”, rather that trying for “no friction at all” (another example of seeking “good” over “perfect” :-).

*It would be done already if it was a wanted one.

Other chores like swatting bugs and and keeping up with the Glasgow Haskell Change-a-thon could also distract from switching to Text - there are only some many hours in each day…

1 Like

…(heh) much like That Formerly Known As FRP - I would have raised the same point if someone had suggested adding one of those packages or libraries to base (e.g. to make windowing, GUI, etc tasks easier).

I want to rip out lazy IO out of base […]

Perhaps some “sample patches” to exemplify the alternatives would be of use in your quest: you can start with the hedis package and its use of that dastardly-lazy IO :-D

But you can already write “one-off scripts with no .cabal file”, right?

Yes: https://cabal.readthedocs.io/en/stable/getting-started.html#run-a-single-file-haskell-script

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.

1 Like

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.

4 Likes

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)

2 Likes

2 posts were split to a new topic: Using more packages by default

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.

4 Likes