Search code examples
haskellcabal

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


Solution

  • 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.