How can I load optimized code in GHCI? - haskell

I am writing a module that relies on optimization. I want to test this module in ghci. But starting ghc in --interactive mode automatically disables optimization; if I compile the module with -O and then try to load it in an interactive session, ghc insists on loading it in interpreted mode.
For a simple test case to distinguish optimized and unoptimized modules, isOptimized below evaluates to True with optimization on, but False with optimization off:
isOptimized :: Bool
isOptimized = g
g :: Bool
g = False
{-# NOINLINE g #-}
{-# RULES "g/True" g = True #-}

Either use ghci -fobject-code -O Test.hs or cabal repl --ghc-options="-fobject-code -O". In more detail:
ghci must be invoked with the -fobject-code flag.
Optimization flag(s) must be given after -fobject-code on the command line, or in an OPTIONS_GHC pragma at the top of the module. Trying ghc --interactive -O -fobject-code produces a warning that "-O conflicts with --interactive; -O ignored." This is perhaps a bug.
If you're working on a cabalized project and using cabal repl, you need to pass the flags either on the command line (i.e. cabal repl --ghc-options="-fobject-code -O") or in a pragma. Cabal (currently) discards optimization flags set in the .cabal file with ghc-options when invoking ghci; in fact, it explicitly sets -O0 instead. This is perhaps a bug.
Note in any case that you sometimes need to force recompilation manually when switching between optimized and unoptimized mode. Build artifacts are, for some reason, not invalidated when the optimization flags change so long as -fobject-code remains on. If, starting from a clean slate, you have -fobject-code set in your .cabal file, run cabal repl which compiles the module, and then remember you need to set -O on the command line and run cabal repl --ghc-options=-O, ghc will happily load the previously-compiled, unoptimized module. This is also perhaps a bug.
The most reliable scenario for testing a single module seems to be to put {-# OPTIONS_GHC -fobject-code -O #-} at the top of the module. You will get optimized code no matter how you invoke ghci. I haven't investigated what happens in multi-module situations where some but not all modules have the pragma.
Incidentally, note that only code in the module is optimized. Even with optimization on, evaluating g in the repl will always produce False, because the repl input is not subject to rewrite rules.

Related

Code that compiles with ghc but not with cabal new-run

I have this program Main.hs:
main :: IO ()
main = do
if False then undefined
else do
let x = 5
print x
When I compile it with ghc Main.hs it compils well generating a Main executable, but when (after initializing cabal with cabal init) I try to make a cabal new-run it gives an error:
$ cabal new-run
Build profile: -w ghc-8.6.5 -O1
In order, the following will be built (use -v for more details):
- ghc-vs-cabal-0.1.0.0 (exe:ghc-vs-cabal) (file Main.hs changed)
Preprocessing executable 'ghc-vs-cabal' for ghc-vs-cabal-0.1.0.0..
Building executable 'ghc-vs-cabal' for ghc-vs-cabal-0.1.0.0..
[1 of 1] Compiling Main ( Main.hs, /home/ivan/ghc_vs_cabal/dist-newstyle/build/x86_64-linux/ghc-8.6.5/ghc-vs-cabal-0.1.0.0/x/ghc-vs-cabal/build/ghc-vs-cabal/ghc-vs-cabal-tmp/Main.o )
Main.hs:4:10: error: Empty 'do' block
|
4 | else do
| ^^
With cabal run it also gives error.
I have cabal version 2.4.0.0:
$ cabal --version
cabal-install version 2.4.0.0
compiled using version 2.4.0.1 of the Cabal library
And ghc version 8.6.5:
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.6.5
Does somebody know what is happening?
I know that I can fix it if I add indentation:
main :: IO ()
main = do
if False then undefined
else do
let x = 5
print x
But I want to know why it compiles with ghc but not with cabal new-run
Your code requires a language extension to parse: NondecreasingIndentation. This extension exists to avoid the awkward runaway effect of nested dos
main :: IO ()
main = do
if False then undefined
else do -- next block should be indented in standard Haskell
let x = 5
print x -- ...but this can easily get out of hand if you do it multiple times
NondecreasingIndentation allows a nested do block to register as nested as long as it's indented as much as the containing block, instead of more than the container.
According to the GHC manual, NondecreasingIndentation is on by default but disabled in Haskell2010 mode (unless explicitly enabled again). I can't find the corresponding cabal documentation, but we can probably guess it defaults to specifying Haskell2010.
You can specify extensions in a source file to be enabled or disabled regardless of external options by adding a pragma like
{-# LANGUAGE NondecreasingIndentation #-}
to the very top of the file.

Enable package-wide extensions in "stack runghc"

If I have the following in my package.yaml file:
default-extensions:
- LambdaCase
I am able to compile my project which makes use of the LambdaCase syntax like this:
myFunction = \case
Nothing -> "empty"
Just x -> x
However, if the project is run with stack runghc, the LambdaCase extension is not respected.
My project has about 200 modules, so I would rather not have to add {-# LANGUAGE LambdaCase #-} to the top of every file.
Is there a way to enable a project-wide GHC extension with stack runghc analogously to the package-wide default-extensions property in package.yaml?
Yes, stack should probably have some better support for this -
see https://github.com/commercialhaskell/stack/issues/3338 .
I'd say the summary is that stack runghc came before stack ghci, it's ended up having a much simpler meaning that does not take cabal files into account at all. Not sure how to make things consistent and intuitive on the commandline without changing the meaning of runghc.
In that issue, I describe a hacky workaround. Copying it here:
Here's a workaround for now. Put the following in ~/.local/bin/stack-run-ghc.sh and make it user executable:
#/bin/sh
ghc $(echo "$*" | sed 's/--interactive//g')
This takes the arguments, removes --interactive, and calls ghc. With this, I can build stack using ghc via the following:
stack ghci --with-ghc stack-run-ghc.sh --ghci-options src/main/Main.hs

How to set ghci options for cabal repl?

I have a haskell project which I compile with -Werror by default. This means that when I run cabal repl it runs with the option -Werror turned on. This means that for example when I evaluate 2 + 2 I get the following error message:
<interactive>:2:3: Warning:
Defaulting the following constraint(s) to type `Integer'
(Num a0) arising from a use of `+'
In the expression: 2 + 2
In an equation for `it': it = 2 + 2
So I need a way to turn on the option, -w or maybe -Wwarn on by default for cabal repl. How do I do this? Also what are the default flags for ghci?
You can set GHCi options in your ~/.ghci file:
:set -w
This overrides the -Wall from cabal repl for me.
My understanding is that ghci has the same defaults a ghc: it's like calling the compiler with no flags. cabal repl gets its defaults from your .cabal file (like ghc-options: -Wall), but this is overridden by your ~/.ghci file.
You can also create a .ghci file in your project directory, with per-project settings there. However, this seems to interact awkwardly with my global ~/.ghci file: adding a set -Wall does not override the :set -w from the global one. I'm not sure if this behavior is intended or I'm just misunderstanding something.

GHC -ddump-splices option — Template Haskell

I'm following the Yesod book, which states:
But by using the -ddump-splices GHC option, we can get an immediate
look at the generated code. A much cleaned up version of it is:
How would I do this? I've tried compiling my file with ghc -XTemplateHaskell -ddump-splices Page.hs, which leaves the directory as follows:
Page Page.hi Page.hs Page.hs~ Page.o
None of these files, however, contain the intermediate code generated by Template Haskell.
http://www.yesodweb.com/book/basics
Meanwhile the behaviour changed and the -ddump-to-file flag in addition to the -ddump-splices flag causes the splices to be written to a file, see Section 9.26 of the current (GHC 8.2.1) documentation for more details.
On older versions of GHC (I didn't check in which version exactly the behaviour changed), -ddump-splices worked differently:
The -ddump-splices option causes GHC to dump the splices to stderr. Unfortunately, the -ddump-to-file flag doesn't affect splices (I don't know whether that has deeper reasons or is just an oversight), so you need to capture the stderr output to save the splices for later investigation,
ghc -XTemplateHaskell -ddump-splices Page.hs 2> Page.dump-splices
on sufficiently bash-like shells.
In large projects doing this for all modules is problematic.
Fortunately, you can dump per module.
This also works in ghci.
You can add this line to the top of your module
{-# OPTIONS_GHC -ddump-splices #-}
It dumps it to stderr.
{-# OPTIONS_GHC -ddump-to-file #-}
is also usefull which puts the dump in a file next to the module with the prefix .dump-simpl.
See reference: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/debugging.html#ghc-flag--ddump-to-file
https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/debugging.html#ghc-flag--ddump-splices
You can add these as separate lines (for easy copy pasting)

Does {-# OPTIONS_HADDOCK hide #-} have any effect on non-exported modules?

Suppose I have a library packaged and built using Cabal, and some module Internal is not in my cabal file's Exposed-modules. Does it then make any difference if I specify a pragma
{-# OPTIONS_HADDOCK hide #-}
at the top of Internal.hs, or is it already automatically hidden according to Haddock?
If it does make a difference, what effect does it have?
It does make a difference if the haddocks of the package are created with the --internal flag to cabal haddock.
$ cabal help haddock
Usage: cabal haddock [FLAGS]
Flags for haddock:
-h --help Show this help text
-v --verbose[=n] Control verbosity (n is 0--3, default verbosity
level is 1)
<snip>
--executables Run haddock for Executables targets
--internal Run haddock for internal modules and include all
symbols
<snip>
If the haddocks are created without the --internal flag, the hide module attribute has no effect: no documentation is created for the module anyway.
If --internal is given, then documentation is created for non-exposed modules except those that specify the hide attribute.
In other words, documentation is generated if hide is not set and either --internal is specified or the module is exported.
The use of --internal for cabal haddock can be specified with cabal install --haddock-internal, or when manually invoking cabal haddock, or with the runhaskell ./Setup.hs ... interface.
Most people just run cabal install with the default options, so only few would observe the difference.

Resources