cabal
cabal copied to clipboard
imported modules in cabal repl with multiple home units - very broken (?)
I'm just an amateur Haskell user (neither beginner nor expert), and wanted to try the new multi-repl support in cabal 3.12. Below is a description of my frustration and some unexpected behavior I encountered while doing so, complete with a minimal reproducer.
In ~/.cabal/config:
multi-repl: True
Project structure:
a $ tree
.
├── a.cabal
├── src
│ └── Main.hs
└── test
└── Spec.hs
3 directories, 3 files
contents of a.cabal:
cabal-version: 3.12
name: a
version: 0.1.0.0
build-type: Simple
common depends
build-depends: , base ^>=4.20.0.0
default-language: Haskell2010
executable a
import: depends
main-is: Main.hs
ghc-options: -main-is Main
hs-source-dirs: src
test-suite a-test
import: depends
main-is: Spec.hs
ghc-options: -main-is Spec
hs-source-dirs: test
build-depends: QuickCheck
contents of src/Main.hs:
module Main where
eight :: Int
eight = 8
main :: IO ()
main = pure ()
contents of test/Spec.hs:
module Spec where
import Test.QuickCheck
nine :: Int
nine = 9
main :: IO ()
main = pure ()
making sure both components work normally:
a $ cabal repl exe:a
Build profile: -w ghc-9.10.1 -O1
In order, the following will be built (use -v for more details):
- a-0.1.0.0 (interactive) (exe:a) (first run)
Preprocessing executable 'a' for a-0.1.0.0...
GHCi, version 9.10.1: https://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/anon/.ghci
[1 of 2] Compiling Main ( src/Main.hs, interpreted )
Ok, one module loaded.
ghci> ei
eight either
ghci> eight
8
ghci>
Leaving GHCi.
a $ cabal repl test:a-test
Build profile: -w ghc-9.10.1 -O1
In order, the following will be built (use -v for more details):
- a-0.1.0.0 (interactive) (test:a-test) (first run)
Configuring test suite 'a-test' for a-0.1.0.0...
Preprocessing test suite 'a-test' for a-0.1.0.0...
GHCi, version 9.10.1: https://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/anon/.ghci
[1 of 2] Compiling Spec ( test/Spec.hs, interpreted )
Ok, one module loaded.
ghci> nine
9
ghci> generate arbitrary :: IO Int
26
ghci>
Leaving GHCi.
eightandnineare both in scope, respectively, as one would expect.
trying multi-repl all target
a $ cabal repl all
Build profile: -w ghc-9.10.1 -O1
In order, the following will be built (use -v for more details):
- a-0.1.0.0 (interactive) (exe:a) (first run)
Preprocessing executable 'a' for a-0.1.0.0...
GHCi, version 9.10.1: https://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/anon/.ghci
[1 of 2] Compiling Main ( src/Main.hs, interpreted )
Ok, one module loaded.
ghci> ei
eight either
ghci> eight
8
ghci> nine
<interactive>:2:1: error: [GHC-88464]
Variable not in scope: nine
ghci>
Leaving GHCi.
- Not looking good. It does have
eight, but notnine.
trying to specificy both units explicitly:
a $ cabal repl exe:a test:a-test
Build profile: -w ghc-9.10.1 -O1
In order, the following will be built (use -v for more details):
- a-0.1.0.0 (interactive) (exe:a) (first run)
- a-0.1.0.0 (interactive) (test:a-test) (first run)
Configuring executable 'a' for a-0.1.0.0...
Preprocessing test suite 'a-test' for a-0.1.0.0...
Preprocessing executable 'a' for a-0.1.0.0...
GHCi, version 9.10.1: https://www.haskell.org/ghc/ :? for help
Command is not supported (yet) in multi-mode
Command is not supported (yet) in multi-mode
Command is not supported (yet) in multi-mode
Loaded GHCi configuration from /home/anon/.ghci
[1 of 4] Compiling Main ( /home/anon/tmp/a/src/Main.hs, interpreted )[a-0.1.0.0-inplace-a]
[2 of 4] Compiling Spec ( /home/anon/tmp/a/test/Spec.hs, interpreted )[a-0.1.0.0-inplace-a-test]
Ok, two modules loaded.
ghci> eight
<interactive>:1:1: error: [GHC-88464]
Variable not in scope: eight
Suggested fix:
Perhaps use data constructor ‘Right’ (imported from Prelude)
ghci> nine
<interactive>:2:1: error: [GHC-88464]
Variable not in scope: nine
ghci>
- ... Huh? Neither of the definitions are in scope. The output also looks different from the previous cabal incantation. Notice also the weird errors about some "Command" that is not supported in multi-mode (not even
-v3prints anything about them). My~/.ghcihappens to have exactly three "commands" in it, all of them copied from the haskellwiki and similar to:def hg \x -> return $ ":!hoogle \"" ++ x ++ "\""...
Even disregarding the obvious inconsistency, I don't think this is how it should behave? I was expecting it to just bring the definitions from both main-is/ghc-options: -main-is into scope (aside: why are both of those needed? This is not intuitive).
And another aside: here we just have two Main modules, but this is of course not representative of a real project. There you have to either import all of your modules by hand in the repl if you want to do repl-driven development, or import them into the Main module and live with an unused import warning for that file. There should really be a way to issue a sequence of commands to cabal repl (including loading / importing modules, IIRC there was one but it does not work because it runs before the modules are compiled and thus has no access to them)...
Seems like things are mostly working as expected here.
- When you write
cabal repl allyou are not loading both units (you need--enable-testsas well to makeallmean that). - GHCi is not fully extended yet to support multiple units, only the basic GHCi commands are supported. This explains the "Command is not supported (yet) in multi-mode" errors. The "context" is the context of the last loaded unit.
It's not clear to me why neither eight or nine is in scope when using the multi-repl but I'm not sure it's worth investigating whilst it isn't consistent about why package ends up providing the final context.
It would be good to extend GHCi to work better with multiple units but that requires someone to perform or fund the work.
Seems like things are mostly working as expected here.
I really appreciate your effort in implementing this feature, however I cannot agree with this.
The behaviour of this feature is currently very surprising (you said it yourself: It's not clear why neither eight or nine is in scope) - and that's clearly a bug.
I understand that bringing this to a polished state requires work and funding, but could we at least agree on removing the "question" label and admitting that a multi-repl without repl functionality (such as definitions being in scope) is of rather dubious utility?
I apologize for my confusion with the labels. I have removed the user-question label.
We just merged a PR which significantly improves GHCi with multi repl: https://gitlab.haskell.org/ghc/ghc/-/merge_requests/14231
In short, your use-case will work as you expect it, as well as all GHCi commands, and the GHCi debugger, which has been patched to work across home units.
We are talking about this during HiW 2025, and we will publish a blog post soon ™ .