Looks good!
I think we could easily have -prelude-is
just like we have -main-is
. Then we could use {-# OPTIONS_GHC -prelude-is=My.Module#-}
for now until some support is added to Cabal.
Looks good!
I think we could easily have -prelude-is
just like we have -main-is
. Then we could use {-# OPTIONS_GHC -prelude-is=My.Module#-}
for now until some support is added to Cabal.
Ok done:
@hsyl20 I’m not sure this warrants a new flag: base-noprelude
+ Cabal mixins to rename any module to Prelude
should do the trick.
@hsyl20 thank you, that was fast! I like the name “prelude-is”. If your MR is accepted, I think it would be good to propose a specific syntax via a language extension, e.g. {-# LANGUAGE PreludeIs My.Module #-}
. It could be done in a further release, if a period of experimentation is required. As for me I would like it as soon as possible. How can I help you?
I dislike that syntax, since no other language pragma takes an argument. Perhaps a better alternative would be a new field in the package description, since this feature is most useful at package scale.
Can you argue why the current solutions are not good enough? As you mention and @bodigrim repeats, we already have mixins which can do this. Are mixins really so bad that we need to introduce a whole new GHC option and Cabal field for one of their use cases?
The last time I tried this it really confused Haskell Language Server. I otherwise liked the approach (though it was a bit tedious setting up for each of our components, it’s mostly a one-off cost). I should revisit that and file some issues!
@Bodigrim base-prelude
seems to be abandoned. Cabal mixins could be used but I like the option of having this directly in GHC. It seems more principled to me. At some point we could have NoImplicitPrelude
the default and Cabal always explicitly specifying -prelude-is
. This would uncouple ghc
and base
more
@Wismill specific syntax is always more difficult to get consensus on. {-# LANGUAGE PreludeIs My.Module #-}
would be the first language pragma to take an argument as @bradrn wrote. Note that with the flag we will have {-# OPTIONS_GHC -prelude-is My.Module #-}
which is quite similar, so special syntax won’t buy us much. Similarly in Cabal, we can use ghc-options: -prelude-is My.Module
without special syntax for now.
How can I help you?
I don’t think adding the flag requires a GHC proposal, but opinions may differ. If it’s deemed necessary, you can help by writing the proposal
specific syntax is always more difficult to get consensus on.
{-# LANGUAGE PreludeIs My.Module #-}
would be the first language pragma to take an argument as @bradrn wrote.
OK, I did not know it would be an issue. {-# OPTIONS_GHC -prelude-is My.Module #-}
is fine, but it is not very elegant, is it?
Can you argue why the current solutions are not good enough? As you mention and @bodigrim repeats, we already have mixins which can do this. Are mixins really so bad that we need to introduce a whole new GHC option and Cabal field for one of their use cases?
@jaror @bodigrim Mixins are a good feature, but I would like to make the Prelude a first class feature. I think nothing beats prelude-is
in term of readability: if I open a Cabal file, I could see easily that a custom prelude is used [^1], even if I did not know about this field. Whereas with mixins you need to known how they work, then understands that the boilerplate only mean using a custom Prelude. Also, how would you specify it when calling ghci
or cabal repl
outside a project? What about the support of mixins in stack?
[^1]: Recommend put it in the first fields.
If we agree using custom Prelude is a good practice, then the main obstacle to a wider adoption is its ergonomics, because the technical solutions already exist.
@hsyl20 has already done a great job in starting a GHC MR. Implementing a Cabal field would be nice; I would volunteer to do it if this thread shows interest to it. In fact the GHC flag and Cabal field are independent features, as the Cabal field can be implemented solely with (implicit) mixins. Using a GHC flag is a better option though, because it gives more flexibility (e.g. using multiple custom preludes in a lib) and make the Prelude feature really first class in GHC.
I don’t believe in a better Prelude that existing one for this reason. However I do use (local) custom prelude per project (.i.e I write my own prelude which could reexport part of a alternative prelude), so there is indeed a rationale for having a better to way to change the implicit prelude.
At the moment it is two lines in a file , the pragma with NoImplicitPrelude and the import the desired prelude. If the point of a new pragma is only to write the two line in one I am not sure there is much benefit.
However, If I can write it ONCE for the all project then I’m all for it. So having a prelude-is
in the cabal file which set automatically NoImplicitPrelude and import the new prelude in every file is a good idea (as long as it allows local prelude.
There is a simpler way to obtain a per-project Prelude today, with no per-module cost whatsoever. Note that the Haskell report quoted above says nothing about where the Prelude
module is obtained? I just ran an experiment:
$ cat Prelude.hs
{-# Language NoImplicitPrelude, PackageImports #-}
module Prelude where
import "base" Prelude (IO, putStrLn)
hello :: IO ()
hello = putStrLn "Hello World!"
$ cat PreludeTest.hs
main = hello
$ ghc PreludeTest.hs
[1 of 3] Compiling Prelude ( Prelude.hs, Prelude.o )
[2 of 3] Compiling Main ( PreludeTest.hs, PreludeTest.o )
[3 of 3] Linking PreludeTest
[mario@fedora tmp]$ ./PreludeTest
Hello World!
[EDIT] I just tested this setup with Cabal, and it works as well. All you need to do is add other-modules: Prelude
stanza. There is something funky about GHC though. When I tried runhaskell
instead of ghc
I got an error:
$ runhaskell PreludeTest.hs
<interactive>:1:1: error:
attempting to use module ‘main:Prelude’ (./Prelude.hs) which is not loaded
I guess I’ll report this bug.
[EDIT] The bug is known.
@blamario I know the trick, but you find its pitfall. See this containers
issue. That is why I did not propose this solution.
The pitfall is clearly a GHCi bug. The correct response is to report and fix the bug, not to work around it.
@blamario I think the issue is already reported. I do not see the point to propose a solution that does not work properly with a current release of GHC. It seems better to use a workaround while the issue is fixed and backported. The mixins is a much better option.
@Wismill We discussed this quickly with the GHC team today. The conclusion was that it would useful to write a GHC proposal to get more feedback on the feature and on unintended consequences (in HLS, etc.).
According to the doc you can have your custom prelude by just having a Prelude.hs
file.
If this is true using a pre made custom prelude is just a matter of having
module Prelude (export X)
where
import YourFavoritePrelude as X
in your project. Unless I am missing something that solves everything doesn’t ? No need to new extension, modify the cabal file etc …
Sorry, didn’t see it. Thanks
This thread made me realize we need at least a single popular signature and implementation that forces everybody to know how use mixins and backpack.
Hi thread, I’m surfacing from a 2-day deep-dive into the subject of custom Prelude.
I agree with the rationale from @Wismill on two points:
base
Prelude be, it’s simple to bash but very hard to fix. Further, everyone will like different preludes (in different applications / contexts) — and an imaginary perfect prelude won’t change that. Haskell should just enable easy switching to alternative preludes. Even better: trivial project-local preludes.I trailed through an assortment of issues on GitHub; and it’s quite difficult to get all of stack build
, stack repl
& HLS working okay with a project-local Prelude.hs
module. I couldn’t do it. As a stop-loss, I’ll instead take the pragmatic approach of saying import MyLocalPrelude
everywhere.
The root issue appears to be #10920: ghci can't load local Prelude module · Issues · Glasgow Haskell Compiler / GHC · GitLab already posted twice in the thread. In stack projects, HLS depends on stack repl
, which in turn depends on ghci
— and the entire “stack” of tooling topples with attempting to use module ‘Prelude’ which is not loaded
. It is a blocker, there’s no viable workaround, I didn’t find any way to configure ghc-options or custom ghci-script for stack repl
to Just Work.
… Now, to the --prelude-is
proposal. Not a huge fan, and I’m not convinced it solves a real issue. The GHC bug is a real issue.