Search code examples
haskellcabal

How to load cabal script with import of hidden package in cabal repl?


I have a script with an external dependency that I can execute with cabal run. I want to load this script in ghci/cabal repl with as few side effects as possible.

This is my script:

#!/usr/bin/env cabal
{- cabal:
build-depends: base
            , split
-}

import Data.List.Split (splitOn)

main :: IO ()
main = do
  let orders = splitOn "x" "axbxc"
  putStrLn $ head orders

I can execute it per Compiling a haskell script with external dependencies without cabal with

$ cabal run script.hs
Warning: Unknown/unsupported 'ghc' version detected (Cabal 3.6.2.0 supports
'ghc' version < 9.4): /home/t/.ghcup/bin/ghc is version 9.4.7
Resolving dependencies...
Build profile: -w ghc-9.4.7 -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..
Preprocessing executable 'script' for fake-package-0..
Building executable 'script' for fake-package-0..
[1 of 1] Compiling Main             ( Main.hs, /tmp/cabal-repl.-4510/dist-newstyle/build/x86_64-linux/ghc-9.4.7/fake-package-0/x/script/build/script/script-tmp/Main.o )
[2 of 2] Linking /tmp/cabal-repl.-4510/dist-newstyle/build/x86_64-linux/ghc-9.4.7/fake-package-0/x/script/build/script/script
a

But if I import it in ghci there are problems with the external dependency:

$ cabal repl
Warning: Unknown/unsupported 'ghc' version detected (Cabal 3.6.2.0 supports
'ghc' version < 9.4): /home/t/.ghcup/bin/ghc is version 9.4.7
Resolving dependencies...
Build profile: -w ghc-9.4.7 -O1
In order, the following will be built (use -v for more details):
 - fake-package-0 (lib) (first run)
Configuring library for fake-package-0..
Preprocessing library for fake-package-0..
Warning: No exposed modules
GHCi, version 9.4.7: https://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /tmp/cabal-repl.-4707/setcwd.ghci
ghci> :load script.hs
[1 of 2] Compiling Main             ( script.hs, interpreted )

script.hs:7:1: error:
    Could not load module ‘Data.List.Split’
    It is a member of the hidden package ‘split-0.2.4’.
    Perhaps you need to add ‘split’ to the build-depends in your .cabal file.
    Use -v (or `:set -v` in ghci) to see a list of the files searched for.
  |
7 | import Data.List.Split (splitOn)
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

Since I have added ‘split’ to the build-depends of my script, is there some way I can point ghci to that part? I'd like to keep things as simple as possible and not add more files. I'd also like to avoid installing libraries on system level to avoid version conflicts and keep everything reproducible.

Things I've tried

How to load imports automatically in cabal repl?

suggests the *M form but that doesn't seem to work for me:

ghci> :load *script.hs
[1 of 2] Compiling Main             ( script.hs, interpreted )

script.hs:7:1: error:
    Could not load module ‘Data.List.Split’
    It is a member of the hidden package ‘split-0.2.4’.
    Perhaps you need to add ‘split’ to the build-depends in your .cabal file.
    Use -v (or `:set -v` in ghci) to see a list of the files searched for.
  |
7 | import Data.List.Split (splitOn)
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.

Per suggestion from Noughtmare:

cabal repl script.hs does not work for me:

$ cabal --version
cabal-install version 3.6.2.0
compiled using version 3.6.2.0 of the Cabal library 
bash-5.1$ cabal repl script.hs 
cabal: 'repl' doesn't take any extra arguments when outside a project:
script.hs

However this works:

$ cabal repl --build-depends split
Resolving dependencies...
Build profile: -w ghc-9.4.7 -O1
In order, the following will be built (use -v for more details):
 - fake-package-0 (lib) (first run)
Configuring library for fake-package-0..
Preprocessing library for fake-package-0..
Warning: No exposed modules
GHCi, version 9.4.7: https://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /tmp/cabal-repl.-11713/setcwd.ghci
ghci> :load script.hs
[1 of 2] Compiling Main             ( script.hs, interpreted )
Ok, one module loaded.

Solution

  • Since cabal 3.8.1.0, you can invoke cabal repl on the script:

    $ cabal repl script.hs
    

    See the last part of the documentation of cabal repl:
    https://cabal.readthedocs.io/en/stable/cabal-commands.html#cabal-repl

    For older cabal versions you can first open a repl with manually specified dependencies and then load the script:

    $ cabal repl --build-depends split
    ...
    ghci> :load script.hs
    [1 of 2] Compiling Main             ( script.hs, interpreted )
    Ok, one module loaded.