How do I handle Haskell Prelude namespace collisions? - haskell

If I want to use readFile from Data.Text.IO, but there's already a readFile in the Prelude, how do I import it, so that it doesn't cause the ambiguity error?
I have a script that just says import Data.Text.IO and then later uses readFile, and I'm testing it in ghci using :load, but it complains about ambiguous function calls.

There are two solutions.
import qualified Data.Text.IO as T
This will give you the Data.Text.IO function as T.readFile. However, if you only plan to use the Data.Text.IO version and never the Prelude version, you can exclude the Prelude version.
import Prelude hiding (readFile)
import Data.Text.IO
An explicit import Prelude will override the default import of Prelude, and you can control which names get imported.

import qualified Data.Text.IO as DTIO, then you can use DTIO.readfile.
see https://wiki.haskell.org/Import for details

Related

How do I figure out which of my imports are from in Haskell?

I have a bunch of imports in my package and need to sort out which ones are coming from a specific package (MissingH). I'm not sure how to do this other than by searching for each on Hoogle. Is there a way to do this programmatically or at the command line by just scanning my package's files?
Here's my list of imports (from all files of my package):
import Control.Arrow
import Control.Exception (assert)
import Control.Monad (unless)
import Control.Monad.Except
import Control.Monad.Zip
import Control.Applicative
import Data.Monoid
import Data.List
import Data.List.Split (splitOn)
import qualified Data.Map as M
import Data.Maybe
import Text.Printf (printf)
import Data.Char (toUpper)
import Data.String.Utils (replace)
import Data.Char (chr, ord)
import Data.List (sort)
import Control.Applicative
import Data.Monoid
import Data.Char
import Data.List
import Data.List.Split (chunksOf)
import Data.String.Utils (replace)
import Text.Printf (printf)
You can ask GHC where it thinks a module comes from (if you have a package already installed providing that module).
% ghc-pkg find-module Data.Maybe
/usr/local/lib/ghc-8.2.2/package.conf.d
base-4.10.1.0
/home/dmwit/.ghc/x86_64-linux-8.2.2/package.conf.d
(no packages)
You can probably cook up a few quick scripts to automate calling this and cover 99.9% of the code people actually write. You might also like to abuse graphmod -- use it to create a module graph, then ignore all the structure of the graph and just iterate over the list of module names it discovers for you and call ghc-pkg on each.
...but it's probably going to be much quicker to just delete MissingH from the dependencies in your cabal file (you are using a build tool like stack or cabal, right??) and see which imports GHC complains about.
If the packages are in Stackage, you can check the module list for a snapshot to get the Map ModuleName [PackageName] correspondence. Yes, a module name may appear in multiple packages per snapshot. Here's an example listing:
https://www.stackage.org/lts-12.12/docs

Cannot find 'Date' type when building Swagger generated API

I am not sure if there is a built in Date type in Haskell or not, it is hard to tell and I can find no documentation.
Here are my import statements
import Data.Aeson (FromJSON (..), ToJSON (..), Value, genericParseJSON, genericToJSON)
import Data.Aeson.Types (Options (..), defaultOptions)
import Data.Function ((&))
import Data.List (stripPrefix)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Generics (Generic)
Here is the line in question
productionEntryProductionDate :: Date
And here is the error I get when trying to run stack build
Not in scope: type constructor or class `Date'
The code I have was from a Web API I generated from some Swagger 2.0 YAML.
I am fairly new to Haskell, so if you need more info please let me know.
Date is not a standard type in Haskell. You can either define your own or you can use Day from the time library. Either way you will need to define the Aeson instances for it yourself. The time library has a parseTimeM function which can do the work for you, but you still need the instance declarations.
Correction: it turns out that Aeson already has instances for both Day and UTCTime types.

GHC import feature or bug

I found that the following code is accepted by GHC:
import Prelude hiding (filter)
import qualified Prelude as P
The idea of these two imports is to make all Prelude functions available as usual, but to require filter to be qualified as P.filter.
I never saw a similar example anywhere, hence my question: is this a feature or a bug in GHC?
Thanks
This is allowed. The import mechanism is very flexible, sometimes surprisingly so.
You can for instance import a module under different names:
import qualified M as A
import qualified M as B
After this, both A.x and B.x will refer to M.x.
Perhaps more surprisingly, you can also import two modules under the same name.
import qualified M as A
import qualified N as A
After this, A.x will refer to either M.x or N.x. If both are defined, an ambiguity error is triggered.
This last feature might seem strange, but after all such ambiguities are already present when importing modules without qualification, so this flexibility does not require any more machinery than the plain import does.
This is a feature and if you search in Github for example you can see this used a lot in the wild.
A widely used idiom is this:
import Data.Text (Text)
import qualified Data.Text as T
This way you don't have to qualify Text in your types and you don't get functions that are conflicting with Prelude functions(like Data.Text.filter, Data.Text.zip etc.).

Haskell *qualified* import of a set of functions

In Haskell, I can import a module qualified by its name or a shortcut name, like so:
import qualified Data.List as List
import qualified Data.Map
I can also import only a select set of functions from a module, or import all functions other than a select set, like so:
import Data.List (sort, intersperse)
import Data.Map hiding (findWithDefault)
Is it possible to import a specific set of functions, like in the import Data.List (sort, intersperse) example above, but to ensure the functions are still identified in a qualified way, such as List.sort and List.intersperse?
Though this does not work, it is the spirit of what I am asking:
import qualified Data.List (sort, intersperse) as List
or perhaps
import qualified Data.List as List (sort, intersperse)
import qualified Data.List as List (sort, intersperse)
This is actually fine and works. The grammar of an import declaration is as follows:
5.3 Import Declarations
impdecl → import [qualified] modid [as modid] [impspec]
qualified and as do not prevent an import specification. This isn't a Haskell2010 addition, as it has been part of the Haskell 98 report.
On the other hand your first example
import qualified Data.List (sort, intersperse) as List
-- qualified impspec! as modid
-- ^ ^
-- +--------------------+
doesn't follow the grammar, as the impspec must be the last element in an import declaration if it's provided.
This is allowed, at least according to the Haskell 2010 Report. First see the examples, which include this one:
import qualified A(x)
Then look up to the actual syntax spec, which indicates that the qualified, as, and "impspec" (the list of imported identifiers or the list of hidden identifiers) are all optional and independent. Thus the syntax genisage describes is actually standard.
Despite the fact that it's not mentioned on https://www.haskell.org/haskellwiki/Import, import qualified Foo as Bar (x, y) seems to work fine for me. I'm running ghc 7.6.3. Maybe that particular wiki page is outdated. If it doesn't work for you, what version of ghc are you using?

How to implicitly import a module

Module A import Data.Char
Module B imports Module A
So Module B automatically imports Data.Char ?
If not do I need to explicitly import Data.Char in Module A?
In my program, the Module B can not access the types from Data.Char
You can export Data.Char from module A.
module A (
-- ... other functions
module Data.Char
-- ... other functions
) where
import Data.Char
Now when you import A, Data.Char will be available.
If you want to access functions and types from Data.Char in your module B, you need to import Data.Char in it, unless the module A you already imported re-exported those functions and/or types that you need in module B.
The import of Data.Char in module A is just for that module itself.

Resources