Building a Better Custom Haskell Prelude
stephendiehl.com
stephendiehl.com
Getting this job done right is essential to Haskell becoming a "hundred-year language".
1. Define a FutureProofing.hs module that anticipates changes to GHC that are, or now were, inevitable, such as Monad becoming a subclass of Applicative, and "fail" moving out of Monad. I redefine MonadIO to depend on Applicative so that I can use "pure" universally, hiding "return" from Prelude.
2. I have a longish list of things I hide from the Prelude, besides "return" (above). I haven't yet crossed the Rubicon of inhibiting the standard Prelude altogether, but I don't allow myself to use the bad parts.
3. I have a GenericIO.hs module that defines a typeclass that allows me to use any type of string for pathnames or data. This eliminates nearly all boilerplate conversions when dealing with the IO library and anticipates the changes that might eventually come to the standard Prelude.
In short, I expect and anticipate the standard library to improve, and will not have to do much work to exploit those improvements when they do arrive. I steer clear of the pitfalls. And unlike the OP, I try to avoid complicating the problem by adding new things to my universal imports; I don't mind having longish import lists at the heads of my modules (and I always enumerate all the names that I import).
Especially the distinction between relative and absolute paths adds a nice safety layer.
The biggest argument against revamping is breaking tons of existing code. Haskell has been trying to gain traction in industry and randomly breaking existing code is a good way to have people lose faith. Now they have locked themselves into roughly "no breaking changes for three years after initial release".
Luckily there has recently been some more progress caused by realizing that online repositories are a great way to validate how much of a breaking change would happen with hypothetical changes, for instance removing the pure/return duality.
It is great that Cabal pushes people to declare what version of the language they are using.
I guess the reason it was still not done is because people do not agree on what the new Prelude should be, if should be a Prelude at all, or if it should be a single one.
* Time types and functions.
* Overloaded (.) and `id`, and some arrow functionality. * More from 'safe'.
* Semigroup.
* String conversions from 'string-conversions', type synonyms for both lazy and strict Text and ByteString types.
* Vector and UUID.
What we don't have:
* The monad transformers by default, although maybe we should.
* Generics. Again maybe we should.
* Bits, Complex.
* All the custom implemented improvements.
* Semiring, DeepSeq, the containers types, concurrency.
Basically our prelude is more conservative, I guess, although it identifies and solves a lot of the same problems. Perhaps that is some common ground to start doing small improvements to the "real" prelude.
Before using stack I was always afraid to come back to a Haskell project after a few months, since using stack that's not a problem. Also, you don't have to worry about different machines, because stack is ensuring that you have the pretty much same build environment (at least the Haskell packages will have the exact same version).
Stack also recently added support for using Nix to solve the problem fixing non-Haskell dependencies for a project.
Why have I never heard about it in all the guides and StackOverflow answers I've had to search through when trying to escape Cabal hell?
http://stackoverflow.com/questions/6364409/why-does-haskells...
map transform . catMaybes . map safeHead
map transform . mapMaybe safeHead(a) be consistent as if the language had type-level literals, which resulted in nicer code in the usual case, but some unsafety on unchecked edge cases, or
(b) give more safety, but force everyone to check for the empty list even when they don't need to.
They went with (a) - it's the type of decision Haskell is (I'd argue incorrectly) criticized for not doing - people complain about having to prove things to their compiler. Of course, in hindsight, and given the language ecosystem now (and that option (b) is instead consistent with all the monad-centric libraries, etc.), (b) seems like a better choice. Which one is better could just as easily change again if empty lists became distinguished at the type-level in Prelude in the future. This is also something that would either crash, or be similarly inconsistent (just return null, causing eventual crashes instead) in any other language. It's notable, though, that the community is making effort to fix these tiny inconsistencies, rather than punting on it for backwards compatibility, as so many other ecosystems do.
That does not make it a good choice. Just a kind of default, but it's a bad default.
I do not know Stephen Diehl but I hope you're right about his capabilities, it would definitely be exciting to see that in Haskell!
Has anyone experience with it, pros, cons?
Mahayana sees itself as going beyond what they might call "individual" or "personal" liberation, in that it sets up a grand goal of liberating all beings. Practitioners hold this ambition in mind, and see the "Hinayana" (small vehicle; a pejorative term used in Mahayana rhetoric to denounce other interpretations of Buddhism) ambition as limited or as merely a first step towards the ultimate goal of universal liberation.
How this relates to the Haskell prelude, I'm not so sure... but yeah, I suppose a "Mahayana prelude" is more grandly ambitious and therefore also more expansive and difficult to realize...
(By the way, in religious studies, Rupert Gethin's book The Foundations of Buddhism has an introductory chapter about Mahayana, and an in depth review is Paul Williams's Mahayana Buddhism: the Doctrinal Foundations.)
In practical terms a "big-vehicle Prelude" is saying "I want to do something much smarter than the original Prelude and I am willing to replace most of the underlying abstractions in the Prelude to do it," which can sometimes mess with code that has to deal with old-prelude and new-prelude subsystems of code. A "small-vehicle Prelude" is much more "I have a couple extra modules here and there that I want to import, and maybe I want to fix a couple of these operators to a slightly more general definition with a typeclass, but largely I want everything to be the same, hence intercompatible with minimum fuss."
"Big Vehicle Prelude - Fix most of the deficiencies in the Prelude by introducing new abstractions that replace large portions of the basic types and class, and generally redefine the way we write Haskell. See numeric-prelude.
Small Vehicle Prelude - Fix the broken parts of the Prelude by building on existing types and classes and masking broken bits. See basic-prelude."
As someone who's only recently started using Haskell seriously, what are some items from this "endless" list of things? Coming from a Standard ML background, one thing about Haskell that I prefer is that the Prelude is so powerful on it's own; SML's set of top-level functions is pretty limited.
This stack overflow answer shows what I'm talking about http://stackoverflow.com/a/22314189/1080531