cabal v2-repl scriptfile.hs

Created on 21 Jul 2019  路  7Comments  路  Source: haskell/cabal

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.

enhancement

Most helpful comment

I'm interested in this feature. Could you give some pointers about how hard it would be to implement? (cc @fendor)

All 7 comments

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:

  • Symlink Script.hs to /tmp/cabal-repl.*/Main.hs

    • doesnt reliably work on windows

    • propagates updates the source file

    • doesnt work to update meta-data

  • Only write cabal.project and fake-package.cabal to /tmp/cabal-repl.*/
    Now use semantically the invocation cabal repl Script.hs --project-file /tmp/cabal-repl.*/cabal.project

    • propagates updates from the source file

    • still doesnt work for updating meta-data

Are 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:

  • Create a fake-package.cabal with the build-depends and main-is: Main.hs.
  • create ghci-script with the content:
    :cd <cwd> :add <cws>/Script.hs
  • Loading this project. This will compile 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:

  • Create library stanza instead of executable in fake-package.cabal.

    • The meta-data part is parsed by executableGrammar, so that does not really work

    • Using a different stanza when opening a repl for the script is counter-intuitive since there is a different support of fields.

Any other good way of handling this?

Was this page helpful?
0 / 5 - 0 ratings