Haskell -- suppress import errors - haskell

I have a bunch of Haskell files I need to compile with GHC, but some import libraries that don't exist. Is there a way to suppress the compiler error: Could not find module, and only make it throw during runtime? Something like -fdefer-type-errors does, but for imports.
Editing the files is not an option at the moment, and most imports are not even used by the program, so would never throw if it compiled.

You can use cabal's mixins to expose other, existing, modules with the names of the modules you desire to exist. For example you might have a file:
module MyLib (someFunc) where
import Module1
import Module2
someFunc :: IO ()
someFunc = putStrLn "someFunc"
So Module1 and Module2 do not actually exist. But you can point those modules to anything, such as Data.Map and Data.Set using the cabal file:
library
exposed-modules: MyLib
-- Modules included in this library but not exported.
-- other-modules:
-- LANGUAGE extensions used by modules in this package.
-- other-extensions:
build-depends: base ^>=4.14.0.0, containers
hs-source-dirs: src
default-language: Haskell2010
mixins:
containers (Data.Map as Module1, Data.Set as Module2)

There is no option in GHC that allows compilation when an imported module can not be found.

Related

Importing sub-packages with stack

I don't understand how to import "sub-packages" in stack (if this is not the correct term, please let me know so I can edit).
Here's the top of a simple file:
{-# LANGUAGE OverloadedStrings #-}
module Conduit where
import Data.Conduit
import qualified Data.Conduit.List as CL
import qualified Data.Conduit.Binary as CB
Two dependencies are listed. In myproject.cabal, I have:
executable myproject
hs-source-dirs: src
main-is: Main.hs
default-language: Haskell2010
build-depends: base >= 4.7 && < 5,
conduit
stack build -v gives me this error:
2018-02-08 13:28:06.923836: [warn] 7 | import qualified Data.Conduit.Binary as CB
I am not sure what to include in the cabal executable directive, each of these throws errors:
build-depends: base >= 4.7 && < 5,
conduit,
conduit.list,
conduit.binary
build-depends: base >= 4.7 && < 5,
conduit,
conduit-list
conduit-binary
Data.Conduit.Binary is a module. It is part of a package called conduit-extra. Packages are what Stack (and cabal-install, were you using that instead) installs, and what you should add to the build-depends of the .cabal file:
build-depends: base >= 4.7 && < 5,
conduit,
conduit-extra
As for Data.Conduit.List, it is part of the conduit package, so you don't need another entry for it. One quick way of clarifying such things is doing a Hoogle search for the module (the package it belongs to will be pointed out in the top bar of the documentation page).
See also: What's the difference between module, package and library in Haskell?; Packages, modules and import in Haskell.

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

Import modules in Haskell

For a Haskell project I've just started, I have two files Main.hs and Lib.hs
However, I often find myself reaching for some modules that I've imported inside Lib while working in Main.
Is there a way to automatically load in Main.hs all the modules already imported inside Lib?
Lib.hs
import System.Random
import Data.List
{-
Lib code here
-}
Main.hs
import Lib -- Importing should automatically imports System.Random and Data.List
main = undefined
Modules can export other modules, including themselves (meaning they export all top level definitions instead of an explicit list of symbols you'd otherwise need to rely on).
module Lib ( module System.Random, module Data.List, module Lib) where
import System.Random
import Data.List
{-
Lib code here
-}

How do I install and test a Haskell package that I'm developing locally?

I'm developing a Haskell package and would like to test it as if it were an installed package. That is, I'd like to be able to install it among my other packages and then either import or :m +.
I can successfully build my package and (apparently) can successfully install it using
cabal install
which reports
Resolving dependencies...
Configuring Exos-0.0.1.0...
Building Exos-0.0.1.0...
Installed Exos-0.0.1.0
but all attempts to import the package then fail with something like (e.g. in GHCi)
<no location info>:
Could not find module ‘Exos’
It is not a module in the current program, or in any known package.
even though I can see a populated Exos-0.0.1.0 folder in my Haskell lib directory. (Even "uninstalling" fails with ghc-pkg unregister, which reports ghc-pkg: cannot find package Exos-0.0.1.0.)
How do I install and test a package that I'm developing locally, so that it behaves like part of my collection of installed Haskell packages — specifically so that I can import it (and "uninstall" it) like any other?
My package has the structure
Exos.cabal
Exos/
Cryo/
Exos.hs
Exos/
Display.hs
Core.hs
with (relevant) contents in Exos.cabal
name: Exos
version: 0.0.1.0
build-type: Simple
- ...
library
exposed-modules: Cryo.Exos,
Cryo.Exos.Display
other-modules: Cryo.Exos.Core
-- other-extensions:
build-depends: base >=4.8,
containers >= 0.5.5.1,
split >= 0.2.2,
MissingH >= 1.3.0.1
-- hs-source-dirs:
default-language: Haskell2010
in Exos.hs
module Cryo.Exos
(
f,
g,
otherFunc
) where
import Cryo.Exos.Core
-- ...
in Core.hs
module Cryo.Exos.Core where
-- ...
and in Display.hs
module Cryo.Exos.Display
(
showSomething,
showSomethingElse
) where
import Data.Char
-- ...
import Cryo.Exos.Core
import Cryo.Exos
FWIW, inside my IDE, I can write an and successfully run "Application" with the following section in the above .cabal file
executable enigma-hs
main-is: Main.hs
build-depends: base >=4.8,
Exos
hs-source-dirs: tests
default-language: Haskell2010
and the following (relevant) code in Exos/tests/Main.hs
module Main where
import System.IO
import Cryo.Exos
import Cryo.Exos.Display
main :: IO ()
main = do
putStr $ showSomething
putStr $ showSomethingElse
-- ...
The error is a simple one: If you look at the Main.hs example where you have successfully imported the module you have
import Cryos.Expos
and not
import Expos -- wrong
that's because, the module you are importing is Cryos.Expos from the package Expos.

How to build and use a bootstrap executable in a Cabal package

I would like to Cabalize a Haskell project in order to upload it to Hackage. It consists of one standard .hs file which builds a bootstrap executable, and eight nonstandard .lhs files which are processed by the bootstrap executable to yield the .hs files which build the production executable.
In other words, my project is a custom literate preprocessor (with HTML markup, code grooming, here documents) which is written in itself. It depends on a bootstrap version which can translate the literate code for the production version, but which is not suitable for general use. So I do not want the bootstrap version to be a separate package; it is meant to be used only once, here.
I have been using a Makefile, which is possible in Cabal but not in the spirit of Cabal. What is a clean way to do this, that takes maximal advantage of the generality of Cabal? I have not seen any suggestions for this in the online documentation, short of either rewriting Distribution.Simple or using a Makefile.
I think that releasing your bootstrap executable as a separate package is the easiest solution, and there are instructions available on how to integrate your custom preprocessor with Cabal.
If you don't want to do that, try making your preprocessor part of Setup.hs (don't forget to set the build type to Custom!). You can run your preprocessor during the configure step. Look at how wxcore does this.
Here's a working example (patterned after wxcore):
Setup.hs:
import Distribution.Simple
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Setup
import Distribution.PackageDescription
import Control.Monad (forM_)
import System.Directory (copyFile)
import System.FilePath (replaceExtension)
main :: IO ()
main = defaultMainWithHooks simpleUserHooks { confHook = myConfHook }
-- Replace 'copyFile' with more complicated logic.
runMyPreprocessor :: FilePath -> IO ()
runMyPreprocessor abcFile = copyFile abcFile (replaceExtension abcFile ".hs")
myConfHook :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags
-> IO LocalBuildInfo
myConfHook (pkgDesc, hbi) flags = do
let extraSrc = extraSrcFiles . packageDescription $ pkgDesc
forM_ extraSrc runMyPreprocessor
confHook simpleUserHooks (pkgDesc, hbi) flags
my-preprocessor.cabal:
name: my-preprocessor
version: 0.1.0.0
build-type: Custom
cabal-version: >=1.8
extra-source-files: Main.abc
executable my-preprocessor
main-is: Main.hs
build-depends: base < 5
Main.abc:
module Main
where
main :: IO ()
main = putStrLn "Hello"

Resources