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

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.

Related

Plugin name lookup behavior change from GHC 8.4 series

[Update: Turns out this was a GHC bug and it is now fixed, slated for the 8.6.4 release: https://ghc.haskell.org/trac/ghc/ticket/16104#comment:8 ]
I'm trying to port a core plugin to GHC 8.6.3, which was last working fine with GHC 8.4 series. Unfortunately, I'm running into issues. Wondering if pluging programming requirements have changed, or is this a regression in GHC itself. I boiled it down to the following example and would like some guidance on how to make this work:
I have the following in file TestPlugin.hs:
{-# LANGUAGE TemplateHaskell #-}
module TestPlugin (plugin) where
import GhcPlugins
import Data.Bits
plugin :: Plugin
plugin = defaultPlugin {installCoreToDos = install}
where install _ todos = return (test : todos)
test = CoreDoPluginPass "Test" check
check :: ModGuts -> CoreM ModGuts
check m = do mbN <- thNameToGhcName 'complement
case mbN of
Just _ -> liftIO $ putStrLn "Found complement!"
Nothing -> error "Failed to locate complement"
return m
And I have a very simple Test.hs file:
{-# OPTIONS_GHC -fplugin TestPlugin #-}
main :: IO ()
main = return ()
With GHC-8.4.2, I have:
$ ghc-8.4.2 --make -package ghc -c TestPlugin.hs
[1 of 1] Compiling TestPlugin ( TestPlugin.hs, TestPlugin.o )
$ ghc-8.4.2 -package ghc -c Test.hs
Found complement!
But with GHC 8.6.3, I get:
$ ghc-8.6.3 --make -package ghc -c TestPlugin.hs
[1 of 1] Compiling TestPlugin ( TestPlugin.hs, TestPlugin.o )
$ ghc-8.6.3 -package ghc -c Test.hs
ghc: panic! (the 'impossible' happened)
(GHC version 8.6.3 for x86_64-apple-darwin):
Failed to locate complement
The problem goes away if I change Test.hs to:
{-# OPTIONS_GHC -fplugin TestPlugin #-}
import Data.Bits -- Should not be required in the client code!
main :: IO ()
main = return ()
That is, if I explicitly import Data.Bits. But tis is quite undesirable, since Test.hs is client code and the users of the plugin have no reason to import all bunch of modules the plugin might need for its own purposes. (In practice, this would require clients to import a whole bunch of irrelevant modules; quite unworkable and not maintainable.)
I've found the following stack-overflow ticket, which seems to suffer from a similar problem: How to replicate the behaviour of 'name in a TH splice However, the answer suggested there is just not OK in this case (and perhaps wasn't really OK there either) since it would require unnecessary changes to client code in my case that is just not reasonable to expect. (Perhaps #JoachimBretner has an idea?) I've also filed this as a GHC ticket (https://ghc.haskell.org/trac/ghc/ticket/16104#ticket), but feedback from the stack-overflow community is greatly appreciated.
Should I be coding my plugin differently? Or is this a GHC regression?
Not a direct answer, but when I need to “hard-code” a name in a GHC plugin, I don’t use TH. Instead, I use findImportedModule and lookupOrig to look it up, e.g. as in
lookupJDITyCon :: TcPluginM Class
lookupJDITyCon = do
Found _ md <- findImportedModule jdiModule Nothing
jdiTcNm <- lookupOrig md (mkTcOcc "JustDoIt")
tcLookupClass jdiTcNm
where
jdiModule = mkModuleName "GHC.JustDoIt"
from the code of my ghc-justdoit plugin.
I use Template Haskell names when the user needs to mention names, e.g. in splices or annotations, that I want to pick up in the plugin. This is what I do in inspection-testing. I discuss this a bit in the appendix of the Inspection Testing paper.

How to use Text.Parsec in GHC-8.2.2 and Cabal-2.0.0.1

As I know Text.ParserCombinators.Parsec is replaced by Text.Parsec
Here, it is my environment
4.9.73-1-MANJARO
The Glorious Glasgow Haskell Compilation System, version 8.2.2
cabal-install version 2.0.0.1
compiled using version 2.0.1.0 of the Cabal library
The following source code is my main.hs
module Main where
import System.Environment
import Text.Parsec
main :: IO ()
main = do
args <- getArgs
putStrLn (readExpr (args !! 0))
and then I compile it
$ ghc -package parsec -o main main.hs
It occurs the following error messages
[1 of 1] Compiling Main ( main.hs, main.o )
main.hs:3:1: error:
Could not find module ‘Text.Parsec’
There are files missing in the ‘parsec-3.1.11’ package,
try running 'ghc-pkg check'.
Use -v to see a list of the files searched for.
|
3 | import Text.Parsec
| ^^^^^^^^^^^^^^^^^^
rm: cannot remove '*.hi': No such file or directory
./run.sh: line 11: ./TestProj: No such file or directory
I make sure I have installed parsec. So I want to ask any mistake I've done?
$ cabal install parsec
Resolving dependencies...
All the requested packages are already installed:
parsec-3.1.11
Use --reinstall if you want to reinstall anyway.
Manjaro might have inherited from Arch's issues with Haskell.
What is going on
Arch installs dynamic libraries, but ghc links statically by default. This is also what the error message "There are files missing in the ... package", indicating that the package exists but does not contain what ghc is looking for.
If I try compiling with the -v verbose flag on, the error message expands to:
ghc -v main.hs
(...)
Locations searched:
Text/Parsec.hs
Text/Parsec.lhs
Text/Parsec.hsig
Text/Parsec.lhsig
/usr/lib/ghc-8.2.2/site-local/parsec-3.1.11/Text/Parsec.hi
(...)
In particular, look into the last reported location, which may be different on your system; if my guess is correct, ghc is looking for a static interface file .hi as the message indicates but there is only a dynamic one .dyn_hi.
Fix
Compile with the -dynamic flag.
ghc -dynamic main.hs
And if that works read this to fix the setup:
https://wiki.archlinux.org/index.php/Haskell
You will have to choose between static and dynamic linking; I don't actually understand the trade-off here.

Why i can't compile with GHC if code contain module definition?

I'am trying to compile a very small haskell code with ghc:
module Comma where
import System.IO
main = do
contents <- getContents
putStr (comma contents)
comma input =
let allLines = lines input
addcomma [x] = x
addcomma (x:xs) = x ++ "," ++ (addcomma xs)
result = addcomma allLines
in result
The command i'm using to compile is :
ghc --make Comma.hs
And i'm getting this answer:
[1 of 1] Compiling Comma ( Comma.hs, Comma.o )
No file is generated, and there is no warning or errors messages.
If i comment the "module Comma where" line from code it compiles correctly:
[1 of 1] Compiling Main ( Comma.hs, Comma.o )
Linking Comma ...
I don't understand what is happening.
I'm using ghc 7,4,1
(Glasgow Haskell Compiler, Version 7.4.1, stage 2 booted by GHC version 7.4.1)
and ubuntu linux.
I appreciate if anyone could tell why doesn't compile with the module definition
GHC compiles the function Main.main to be the entry point of an executable. When you omit the module declaration, Module Main where is implicitly inserted for you.
But when you explicitly name it something other than Main ghc doesn't find an entry point.
My usual workflow is to use ghci (or ghci + emacs) instead for these snippets which let's you bypass this issue entirely. Alternatively, you could compile with -main-is Comma to explicitly tell ghc to use the Comma module.
No file is generated
Are you sure? I would expect that at least Comma.o and Comma.hi are generated. The former contains the compiled code ready to be linked into an executable, and the latter contains interface information that ghc uses to typecheck modules that import the module Comma.
However, ghc will only link the compiled modules into an executable if there is a main function. By default, that means a function named main in a module named Main. If you don't put an explicit module name, the name Main is assumed, and that's why your test works when you delete the module Comma where line.
To compile and link the Comma.hs file you can either use module Main where instead of module Comma where, or you can use the -main-is flag to tell ghc that Comma.main is to be the main function:
ghc --make -main-is Comma Comma.hs
Or:
ghc --make -main-is Comma.main Comma.hs
If you have a main definition in your file and you want to compile it to an executable you need can only have module Main where.

cabal FFI dependency

I am making a small Haskell game in Windows, where I would like to respond each time the user presses a key. Because getChar behaves strangely on Windows, I use FFI to get access to getch in conio.h, as described here. The relevant code is:
foreign import ccall unsafe "conio.h getch" c_getch :: IO CInt
This works fine, when I run it in ghci, or compile it with ghc. I also want to try making a cabal package out of it, so extending from this question, I include the following in my cabal file:
...
executable noughts
Includes: conio.h
Extra-libraries conio
...
But when I run cabal configure, it tells me:
cabal: Missing dependency on a foreign library:
* Missing C library: conio
It makes sense, because in my haskell platform directory, under ...\Haskell Platform\2012.4.0.0\mingw there is a conio.h file under the include directory, but no other conio file to provide the object code.
Am I doing this the right way, and if so, how can I find out which library to include in my cabal file?
First off, there is not always a one-to-one mapping between C header files and libraries. In this case, the functions declared in conio.h can be found in various runtime libraries, such as crtdll (deprecated) or msvcrt (preferred, I guess).
With the Haskell Platform on Windows, Cabal will look for these libraries in .\mingw\lib (under your Haskell Platform directory): if you ask for msvcrt, it will look for .\mingw\lib\libmsvcrt.a. This specific library should already be shipped with your Haskell Platform. (If you want to point to other directories with lib*.a files, you can use Cabal's --extra-lib-dirs option.)
A tiny example of this would be as follows; this is Main.hs:
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C.Types
foreign import ccall unsafe "conio.h _putch" c_putch :: CInt -> IO ()
main :: IO ()
main = do
c_putch . toEnum . fromEnum $ '!'
c_putch . toEnum . fromEnum $ '\n'
And this would be something-awesome.cabal:
name: something-awesome
version: 0.1.0.0
build-type: Simple
cabal-version: >=1.8
executable yay
main-is: Main.hs
build-depends: base ==4.5.*
includes: conio.h
extra-libraries: msvcrt
This should work fine:
c:\tmp\something-awesome> dir /B
Main.hs
something-awesome.cabal
c:\tmp\something-awesome> cabal configure
Resolving dependencies...
Configuring something-awesome-0.1.0.0...
c:\tmp\something-awesome> cabal build
Building something-awesome-0.1.0.0...
Preprocessing executable 'yay' for something-awesome-0.1.0.0...
[1 of 1] Compiling Main ( Main.hs, dist\build\yay\yay-tmp\Main.o )
Linking dist\build\yay\yay.exe ...
c:\tmp\something-awesome> dist\build\yay\yay.exe
!

Including data files in cabal builds

I have a package with the following structure (okay, this is greatly simplified, but...)
app/
src/
Main.hs
data/
data.txt
app.cabal
Paths_app.hs
Setup.hs
In Paths_app.hs I have:
module Paths_app where
getDataFileName :: FilePath -> IO FilePath
getDataFileName = return
and in Main.hs I have:
module Main where
import Paths_app
main = do
file <- getDataFileName "data/data.txt"
data <- readFile file
putStrLn $ "Your data is: " ++ data
the relevant parts of my app.cabal file look like this:
name: app
version: 1.0
build-type: Simple
data-files: data/data.txt
executable foo
build-depends: base, haskell98
main-is: Main.hs
hs-source-dirs: src
This builds fine (using cabal configure followed by cabal install) but the executable complains that it can't find the data.txt file. I've tried replacing the line
file <- getDataFileName "data/data.txt"
with
file <- getDataFileName "data.txt"
but the same thing occurs. Is there something obvious I'm doing wrong?
I've tried to reproduce it, but it works fine for me.
In the setup you describe, I had to drop the dependency on haskell98 as both base and haskell98 were providing Prelude. Furthermore, the file Main wouldn't compile as it used the keyword data as a variable name, so I renamed the variable to dat. But then it worked just fine.
Some info on my setup:
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.4.1
$ cabal --version
cabal-install version 0.13.3
using version 1.14.0 of the Cabal library
$ ls ~/.cabal/bin/
... foo ...
$ ls ~/.cabal/share/app-1.0/data/
data.txt
The problem was that I was building on a Windows system, and when I used the filename returned by getDataFileName to load data into my program, I wasn't escaping the backslashes.

Resources