Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Analogue of cabal repl #130

Closed
UnkindPartition opened this issue May 30, 2015 · 16 comments
Closed

Analogue of cabal repl #130

UnkindPartition opened this issue May 30, 2015 · 16 comments
Assignees
Milestone

Comments

@UnkindPartition
Copy link
Contributor

IIUC stack ghci simply calls ghci with the stack's package db.

cabal repl is more than that: if run in a directory with a cabal file, it'll enable the extensions listed in the cabal file (super-useful) and also load all package's modules (moderately useful).

@snoyberg
Copy link
Contributor

LGTM. I'd argue for making this the same command as stack ghci to avoid confusion (why does ghci work differently than repl?) and instead add a flag to disable this functionality if desired.

Assigning to @DanBurton for now, though someone else may wish to take a crack at it instead.

@snoyberg snoyberg added this to the Second release milestone May 31, 2015
@chrisdone
Copy link
Member

Yeah, although I vote not to copy Cabal's approach much.

Things that are annoying with cabal repl:

  1. Forced separation of all targets: When I work on a project, I work on everything. The library, executables, tests, and I switch between freely. cabal repl only sets the extensions and load paths for just one target that you pick (by default library). Sensible but in practice a pain.
  2. Loading all the modules when you start up from scratch. This is a complete waste of my time. Every time I enable a new package and restart GHCi I have to wait for it to load everything all over again. Duncan told me this is a consequence of the way Cabal uses the build system to launch GHCi and is not easy to disable.
  3. Failing to start when it fails to load the modules from step 2. That's immensely frustrating.

So I'd vote by default:

  • Enable extensions in all targets.
  • Enable load paths in all targets.
  • Optionally support target-specific initializing.
  • Don't load all the modules when you start it.

In other words, just work.

@UnkindPartition
Copy link
Contributor Author

What you're saying is valid. I sometimes want this behavior. But I also often want the opposite :)

  • Enabing extensions in all targets is often convenient, but:
    • Sometimes extensions from one package may break another. I'm sure you're aware of that; if not, I can give examples. Extensions may also override/cancel one another.
    • It may happen that your code works in ghci, but doesn't build, because it requires extension that was not listed in that package's cabal file (but was listed in another one)
  • Enable load paths in all targets — IIUC this means unnecessary interpreting more code than needed. E.g. there are packages A and B, both pretty big ones, and B depends on A. If I'm interested in working on B (but not A) at this time, I'd rather use the compiled version of A and not wait till ghci loads all of A's modules.
  • I'm not sure what you mean by target-specific initializing.
  • Loading all modules at start is a great way to check that your project compiles. To do that otherwise, you need either to build (which is slow compared to ghci, esp. rebuilding vs reloading), or to load all root modules manually. This specific thing can probably be addressed by a custom ghci command.

@chrisdone
Copy link
Member

Sometimes extensions from one package may break another.

I assume you meant target here instead of package. Yes, indeed. Sometimes that can happen.

Enable load paths in all targets — IIUC this means unnecessary interpreting more code than needed. E.g. there are packages A and B, both pretty big ones, and B depends on A. If I'm interested in working on B (but not A) at this time, I'd rather use the compiled version of A and not wait till ghci loads all of A's modules.

Okay, I'm not sure we're talking about the same thing. A target is a section in the cabal file. I'm talking about targets within one package here.

Loading all modules at start is a great way to check that your project compiles. To do that otherwise, you need either to build (which is slow compared to ghci, esp. rebuilding vs reloading), or to load all root modules manually. This specific thing can probably be addressed by a custom ghci command.

Granted, it should be optional in any case.

@UnkindPartition
Copy link
Contributor Author

Oh, ok. I somehow assumed you were talking about multipe local cabal packages specified in a single stack.yaml.

Then there's much less disagreement here.

@chrisdone
Copy link
Member

Okies. Actually loading all the packages is something @nh2 has been asking about -- it has some use in debugging to load everything into one big ghci session. I guess that could be another feature.

@chrisdone
Copy link
Member

Should include the autogen dirs:

-idist-stack/Cabal-1.18.1.5/build/autogen/
-optP-include -optPdist-stack/Cabal-1.18.1.5/build/autogen/cabal_macros.h

@snoyberg snoyberg assigned dysinger and unassigned DanBurton Jun 1, 2015
@snoyberg snoyberg modified the milestones: Third release, Second release Jun 5, 2015
@dysinger
Copy link
Contributor

dysinger commented Jun 6, 2015

So something like:

# set paths & extensions for all targets but don't load any modules (could fail but probably won't)
stack repl 
# set paths & extensions for exe:myproject but don't load the modules (in case default mode fails)
stack repl --target=exe:filename
# set paths & extensions for exe:myproject & load the modules (the cabal way)
stack repl --load --target=exe:filename

@chrisdone
Copy link
Member

Works for me!

Though I think if the load fails it shouldn't just bail out. E.g.

chris@retina:~$ ghci X.hs
GHCi, version 7.8.4: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
unknown option: 'c'
[1 of 1] Compiling X                ( X.hs, X.o )

X.hs:6:5:
    No instance for (Num ()) arising from the literal ‘1’
    In the expression: 1
    In an equation for ‘x’: x = 1
Failed, modules loaded: none.
Prelude> 

The user can just fix this and run :r and be done instead of restarting everything from scratch.

@hesselink
Copy link
Contributor

I've never had great luck with cabal repl, so if stack ghci can improve on that, I'd love it. My use case is usually something like this: I'm developing a set of packages together, and would like to load a file from one of them in the repl. The files it depends on from its package, and preferably also the other packages in the set I'm working on, should come from source, not the package database. For anything else, the package database should be used like now.

I can see how sometimes it can be beneficial to use the compiled version of a package instead, since that speeds things up, so a flag either way looks good.

@chrisdone
Copy link
Member

@hesselink Indeed, it seems a lot of the time one could load up GHCi with -i./package1/src -i./package2/src and optimistically assume the extensions will be non-conflicting. I think that cabal_macros.h may also cascade reasonably.

Brainstorming, perhaps:

$ stack repl
  • In the root directory: load up all packages specified in stack.yaml.
  • In a project-specific directory: load up just that package.

Then

$ stack repl foo bar

Load up the foo and bar packages together, with order being of significance for the order of -i and -X/-XNo specifications.

This is also analogous to stack build in terms of determining targets.

(Or s/repl/ghci, whatever is preferred.)

@acfoltzer
Copy link
Contributor

Big 👍 to this in general, and to the improvements laid out in this thread. The biggest current pain point for me is the time it takes to C-c C-l after changing anything when running cabal repl in haskell-interactive-mode.

@hesselink
Copy link
Contributor

@chrisdone We use a script that basically uses that approach: it adds all package source directories with -i, as well as all cabal macros and autogen directories. We've used it with about 30 packages at the same time, and never had trouble with conflicts between them. We don't specify extensions in cabal files (we put them in the source files instead) so I can't say anything about that.

@chrisdone
Copy link
Member

Cool, sounds like we're all onboard with this going forward.

@hesselink We've been taking a similar approach of specifying extensions per-file too in anticipation of loading everything on at once for debugging purposes.

@ndmitchell
Copy link
Contributor

Note that ghcid integration requires stack ghci to work as outlined above and load everything up. Requested at ndmitchell/ghcid#38

@snoyberg
Copy link
Contributor

This has been merged in, let's start tracking improvements in new issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants