Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import rather than load modules on startup with 'stack ghci'?

I have a haskell package called prime-tools. When I use stack ghci inside the package directory, I expect it to open up an interactive ghci and automatically import prime-tools. Instead, I find that it loads all of the modules declared in the .cabal file.

For example, here is the extract from my .cabal file showing which modules are declared:

library
  -- Modules exported by the library.
  exposed-modules:     PrimeTools.MathStuff, PrimeTools.Factors, PrimeTools.PQTrials, PrimeTools.Main, PrimeTools.Base, PrimeTools.Lucas

  -- Modules included in this library but not exported.
  other-modules:       PrimeTools.Extras

And this is what happens as I receive the ghci> prompt after running stack ghci in the project folder:

Ok, modules loaded: PrimeTools.MathStuff, PrimeTools.Factors, PrimeTools.PQTrials, PrimeTools.Main, PrimeTools.Base, PrimeTools.Lucas, PrimeTools.Extras.
ghci> 

The problem with loading the modules instead of import prime-tools is that I can now use all functions defined in all modules whether or not they are exported.

An example of the issues arising from this distinction: there are two modules in package prime-tools which have implementations of a function called pfactor. One of them is exported, and intended to be used by the end user of the package, while the other is for internal use only and not exported.

Before someone comments, there is good reason to have two implementations of pfactor, but it's not relevant to my question.


My question: how can I use stack to automatically start up a ghci environment with the local version of ghc and import the package whose folder I run the command in?

My desired behaviour would be equivalent to running the following sequence of commands:

stack ghci
ghci> :module -PrimeTools.MathStuff
ghci> :module -PrimeTools.Factors
ghci> :module -PrimeTools.PQTrials
ghci> :module -PrimeTools.Main
ghci> :module -PrimeTools.Base
ghci> :module -PrimeTools.Lucas
ghci> :module -PrimeTools.Extras
ghci> import PrimeTools.MathStuff
ghci> import PrimeTools.Factors
ghci> import PrimeTools.PQTrials
ghci> import PrimeTools.Main
ghci> import PrimeTools.Base
ghci> import PrimeTools.Lucas

The key here is that I want to import the exposed-modules declared in the .cabal file and not to load any modules. I don't mind if the other-modules are also imported, though. Is there a way I can do this using stack without having to run this long sequence of commands every time?

like image 460
Myridium Avatar asked Oct 18 '22 14:10

Myridium


1 Answers

A reasonable workaround is defining a custom GHCi macro for importing your modules the way you want it. Create a .ghci file in your project root along these lines:

:{
:def deload (\_ -> return 
    ":module -PrimeTools.MathStuff\n\
    \import PrimeTools.MathStuff"
    )
:}

With this, the :deload command in GHCi will remove from scope and then re-import PrimeTools.MathStuff -- you can add as many modules as you want to the list. Though I have written this using multiline string syntax, you can have any String -> IO String expression within the parentheses, so feel free to spell or extend it however you see fit.

like image 134
duplode Avatar answered Nov 15 '22 08:11

duplode