Import modules in Haskell - 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
-}

Related

Haskell -- suppress import errors

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.

How to diagnose "Perhaps you need to add xxx to the build-depends in your .cabal file", when it is already in the cabal file?

I think the only interesting bits are my imports and my cabal file. Here are the imports and the demonstration of how I would use the problematic import (Database.CQL.IO.Log).
module FDS.Database.Cassandra where
import Prelude hiding(init)
import Database.CQL.IO as Client hiding(Logger)
import Database.CQL.IO.Log as CQLLog
import qualified Database.CQL.Protocol as CQL
import Numeric.Natural
import System.Logger (Logger)
cqlLogger :: Logger -> CQLLog.Logger
cqlLogger logger = undefined
However, I get the error:
src/FDS/Database/Cassandra.hs:7:1: error:
Could not load module `Database.CQL.IO.Log'
It is a member of the hidden package `cql-io-1.1.0'.
Perhaps you need to add `cql-io' to the build-depends in your .cabal file.
Use -v to see a list of the files searched for.
|
7 | import Database.CQL.IO.Log as CQLLog
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
But as we can see from the cabal file, it is there:
library
ghc-options: -Wall -Wtabs -Wincomplete-record-updates
default-extensions:
OverloadedStrings
exposed-modules:
FDS
, FDS.Config.Core
, FDS.Config.Dhall
, FDS.Data.Util
, FDS.Database.Cassandra
other-modules:
FDS.Data.Hobo.Defs
build-depends:
prelude
, base-noprelude ^>=4.12
, bytestring ^>=0.10.8.2
, conduit ^>=1.3.1
, containers ^>=0.6
, cql ^>=4.0.1
, cql-io ^>=1.1.0
One thing to note, I do have cql-io in my extra-deps in stack.yaml, as the latest version wasn't yet in LTS.
Q&A from Comments
Q Are there other components in your cabal file (e.g. executables, benchmarks, test suites)?
A Yes
Q Do they also use FDS.Database.Cassandra (but perhaps without depending on cql-io)?
A Not yet, but plan to later. So I haven't touched the other components yet.
Q Does the version of cql-io chosen by your build tool still export Database.CQL.IO.Log?
A It seems to do so.
Q What is the exact command you are running when you see that error?
A stack --nix build The only interesting bit that --nix is doing (AFAIK) is pulling in required system packages, e.g., OpenSSL.
The comments above were very insightful for the general case of the question (as posed); the answer being, sub-libraries that are recently supported by cabal may not have visibility: true declared.
But in my specific case, the answer is to look at the problematic library's re-exports. I could get around this issue because the cql-io authors re-exported Logger (..) and LogLevel(..) from the main library.
So that would allow me to write my code.
An even better answer that is very specific to my situation, as I was trying to use TinyLog, is that there is a library for that already ... here is the code from that library that demonstrates how to get around the issue (and solves the problem for me completely, as I now shouldn't have to write any code).
Here is the relevant excerpt:
module Database.CQL.IO.Tinylog (mkLogger) where
import Data.ByteString.Builder
import Data.ByteString.Lazy (ByteString)
import Database.CQL.IO (Logger (..), LogLevel (..))
import Database.CQL.IO.Hexdump
import qualified Data.ByteString.Lazy as L
import qualified System.Logger as Tiny
-- | Create a cql-io 'Logger' that delegates log messages to
-- the given tinylog 'Tiny.Logger'. Requests and responses are
-- logged on 'Tiny.Trace' level.
mkLogger :: Tiny.Logger -> Logger
mkLogger l = Logger
{ logMessage = tinylogMessage l
, logRequest = tinylogRequest l
, logResponse = tinylogResponse l
}
And here is how I adjusted my imports in the example above to confirm and get GHC happy (though I will scrap this now in favor of using cql-io-tinylog):
import Prelude hiding(init, log)
import Database.CQL.IO hiding(Logger)
import qualified Database.CQL.IO as CQLIO
import qualified Database.CQL.Protocol as CQL
import Numeric.Natural
import System.Logger hiding(defSettings)

Importing a number of modules at once

I have a number of modules under the same folder:
/src/Web/MyLib/Types/Entity1.hs
/src/Web/MyLib/Types/Entity2.hs
/src/Web/MyLib/Types/Entity3.hs
...
Most of them require importing the same modules such as Data.Time, UUID and others. Instead of importing those models to each of the modules under /src/Web/MyLib/Types/, is there any way to create one base module, say, /src/Web/MyLib/Types/Base.hs, import all those modules (Data.Time, UUID, ...) to it and then only import Base to EntityX? I've tried it and failed. Maybe I did something wrong.
Here's an example, taken from Control.Lens, which achieves what you want: it imports everything in a base module and re-exports everything.
module Control.Lens
( module Control.Lens.At
, module Control.Lens.Cons
, module Control.Lens.Each
-- ...
) where
import Control.Lens.At
import Control.Lens.Cons
import Control.Lens.Each
-- ...

import a whole module at one time with Haskell

I'm embarrassed with a library problem with Haskell.
I finished a library made of several files
src/MyLib/Firstbib.hs
src/MyLib/Secondbib.hs
...
src/MyLib/Lastbib.hs
At this time, After cabal install I can import each file separatly with
import MyLib.Firstbib
import MyLib.Secondbib
import MyLib.Lastbib
every thing is OK
Now, I would like to import all these part of MyLib in a simple import :
import MyLib
and I can't reach to make it.
I tried to create a file named src/MyLib.hs containing :
module MyLib where
import MyLib.Types
import MyLib.Functions
import MyLib.Algo.Line
import MyLib.Algo.Point
and expose it with Cabal
Library
-- Modules exported by the library.
Hs-Source-Dirs: src
Exposed-modules: MyLib
, MyLib.Functions
, MyLib.Types
, MyLib.Algo.Line
, MyLib.Algo.Point
but it doesn't work.!
What it the correct way to import many files with only one module import (as for Gtk2Hs for example)?
This is how MyLib should look like -- maybe with different indentation:
module MyLib
(module MyLib.Types
,module MyLib.Functions
,module MyLib.Algo.Line
,module MyLib.Algo.Point
) where
import MyLib.Types
import MyLib.Functions
import MyLib.Algo.Line
import MyLib.Algo.Point
What happens is that when you put a module like that in your export list, you export all the symbols that your module knows about it.
You could potentially scope what part of this module you export, for example:
module ExampleLib
(module Data.Maybe
) where
import Data.Maybe (fromJust)
The above will just re-export fromJust from Data.Maybe, not the whole Data.Maybe module.

Could not find module, it is a member of the hidden package haskell98

When I try to compile a simple source file with import IO or import Random, the build fails with an error message like this:
Could not find module 'IO'
It is a member of the hidden package 'haskell98-2.0.0.1'
Use -v to see a list of the files searched for
The module names changed at some point. You probably want import System.IO and import System.Random instead.
Here is the module hierarchy for the standard libraries in GHC 7.6.1.

Resources