cabal v2-repl scriptfile.hs outside project to load a scriptfile.hs into repl (GHCi).
Suppose I have a script file like:
{- cabal:
build-depends: base, splitmix
-}
import Data.List (unfoldr)
import Data.Word (Word64)
import System.Random.SplitMix (nextWord64, mkSMGen)
numbers :: [Word64]
numbers = unfoldr (Just . nextWord64) (mkSMGen 42)
main :: IO ()
main = print $ take 10 numbers
cabal v2-run -v0 scriptfile.hs works perfectly, however it takes quite a lot of time, 10s on my machine!
% time cabal v2-run -v0 ExRun.hs
[1275548033995301424,10417309031967933079,2112719111588962399,2726445820918627087,4609004260007739600,11074269206337254866,9733109294540808081,6450629194222476823,8084222243108663947,16253064923614931039]
cabal v2-run -v0 ExRun.hs 10,70s user 1,01s system 99% cpu 11,724 total
Slowness is one issue, after all there's compiling involved. It however makes development of scriptfiles extremely painful.
Yet, if the following worked, the development would be a lot nicer (repl ftw):
% cabal v2-repl ExRun.hs
Resolving dependencies...
Build profile: -w ghc-8.6.5 -O1
In order, the following will be built (use -v for more details):
- fake-package-0 (exe:script) (first run)
Configuring executable 'script' for fake-package-0..
...
GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling Main ( ExRun.hs, interpreted )
Ok, one module loaded.
*Main>
*Main> main
[1275548033995301424,10417309031967933079,2112719111588962399,2726445820918627087,4609004260007739600,11074269206337254866,9733109294540808081,6450629194222476823,8084222243108663947,16253064923614931039]
worked, it would be super great.
For now, I try to cabal install --lib the dependencies, and use raw ghci.
I'm interested in this feature. Could you give some pointers about how hard it would be to implement? (cc @fendor)
I intend to work on this.
The implementation of the scriptfile feature seems to be mainly in CmdInstall. It sets up a fake project by essentially writing a *.cabal file to a temporary location and then building this fake project.
First, we should move implementation details from CmdInstall to its own module, proposing: CmdScript.hs.
The implementation itself seems trivial (we will see), the only difficulty I anticipate is to detect changes in the meta-data section of the script on reload (e.g. :r in the ghci session).
The fake package stuff is better put into Distribution.Client.FakePackage something like that. CmdScript would be confusing as there could be cabal script functionality (but it's part of run).
It's worth to make clear to one self how cabal v2-build, cabal v2-run and cabal v2-repl behave outside and inside project. Perfectly these won't have different behaviors / cli interfaces, and I think the easiest way to get there is to abstract common parts more heavily.
so, the first implementation was actually rather trivial.
The current mechanism is to copy the file to some /tmp/cabal-repl. directory and generating a very basic fake-package.cabal. So, we can just open a repl session in that project context. (Although, admittedly, it doesnt make sense to set the cwd to /tmp/cabal-repl. but that is a task for later).
The hard problem is to use :r in the repl session. I would expect that this re-compiles changes, such as source changes and changes to the meta-data.
However, since the source file is copied, neither of these changes can be detected. I had the following ideas:
Script.hs to /tmp/cabal-repl.*/Main.hscabal.project and fake-package.cabal to /tmp/cabal-repl.*/cabal repl Script.hs --project-file /tmp/cabal-repl.*/cabal.projectAre there more options? Can we hook somehow into the reload command of the repl-session to automatically get notified about changes to Script.hs ?
Btw, stack manages to do both, on :r changes to the source file and meta-data are reloaded appropriately.
It's worth to make clear to one self how cabal v2-build, cabal v2-run and cabal v2-repl behave outside and inside project.
they are quite similar indeed!
It is ok to not support updating on meta-data change. cabal repl doesn't update anything when you update .cabal file either. Changing meta-data might change everything in GHCi setup. In other word: let's not try hook anything to :r command. I say that's out-of-scope.
One way to approach this is maybe to make cabal repl Script.hs to load current project and the Script.hs first. Then no-project case (this issue) would be cabal repl /absolute/path/to/Script.hs in the fake project context.
So, workflow is roughly as follows cabal repl Script.hs:
fake-package.cabal with the build-depends and main-is: Main.hs.
:cd <cwd>
:add <cws>/Script.hs
Main.hs as well as <cwd>/Script.hs and add Script.hs to the repl and set the working dir correctly. Changes to Script.hs are detected on :r.What I dont like about this is that two files are loaded, Main.hs and <cwd>/Script.hs. It seems I cant set main-is: <cwd>/Script.hs, according to the docs, and I admit that I prefer it that way.
However, then we have to set some main-is and load this file on cabal repl Script.hs.
A work-around I have been thinking about:
library stanza instead of executable in fake-package.cabal.executableGrammar, so that does not really workAny other good way of handling this?
Most helpful comment
I'm interested in this feature. Could you give some pointers about how hard it would be to implement? (cc @fendor)