Ghci on acid defines in its .gchi
:set -XNoImplicitPrelude
What is the potential benefit/reason one might have for doing so ?
There is no other way to completely avoid importing the Prelude. Even the seemingly-effective
import Prelude ()
which is an explicit import (hence overrides the implicit one) and defines no names nevertheless puts a bunch of class instances in scope that may not be desired.
Avoiding the standard prelude completely is useful when you want to play around with alternate preludes; or when you want to overload syntax using other GHC extensions; or in other niche situations. Avoiding the prelude can also be useful if you plan on using many functions that happen to be named the same as the ones in the prelude, and would like to avoid qualifying them everywhere (though the lesser import Prelude () would suffice in many such situations).
Related
Almost every module in our code base has imports such as:
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Text as Text
I would like to define a local prelude so that Map, Set and Text are available to the modules importing that prelude. Apparently there is no way to do that in Haskell. So I am wondering how do people solve this problem in large Haskell code bases.
I'm going to answer this question, interpreted as literally as possible:
How do people solve this problem in large Haskell code bases?
Answer: they write
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Text as Text
at the top of each module which needs Map, Set, and Text.
In my experience, managing imports is not a significant part of the difficulty of working with large codebases. The effort of jumping to the import list and adding a line for Data.Map when you discover you need it is absolutely swamped by the effort of finding the right place in the codebase to make changes, knowing the full breadth of the codebase so you don't duplicate efforts, and finding ways to test small chunks of a large application in isolation.
Compared to the proposed alternative in the other answer (CPP), this way also has some technical advantages:
Less project lead-in time. The fewer surprises there are for the humans who join onto your project, the quicker they can get up and running and be independently useful.
Better tool support. If I see Foo.bar as an identifier somewhere, I can use my text editor's regex search to find out what import line made the Foo namespace available without fancy additions to include #included files. If I want to find all the files that depend on Some.Fancy.Module, I can learn that by grepping for Some.Fancy.Module. Build systems that do change detection don't need to know about the extra .h file when computing which files to watch. And so forth.
Fewer spurious rebuilds. If you have more imports than you actually use, this can cause GHC to rebuild your module even when it need not be rebuilt.
One solution is to define the import list in a CPP header.
N.B.: This answer is just to show what is technically possible; Daniel Wagner's answer is generally the better alternative.
For a package-level example:
my-pkg/
my-pkg.cabal
include/imports.h
src/MyModule.hs
...
include/imports.h:
import Control.Applicative
import Data.Maybe
import Data.Char
In my-pkg.cabal, components (library, executable, test, ...) have a include-dirs field (that in turn correspond to some GHC option):
library
...
include-dirs: include
Then you can use that header in any module:
{-# LANGUAGE CPP #-}
module MyModule where
#include "imports.h"
-- your code here
mymaybe = maybe
When trying to use what are called "generic" list functions in the Haskell prelude, I get an out of scope error - for instance when trying to use genericDrop, genericTake and so on.
Perhaps I need to import a module or something (but I can see no mention of that in the prelude docs or by googling)
Yes, I believe you need:
import Data.List
In general, when I need to figure out which module to import, I find that hoogle is very useful. You can search for a particular function, and it will take you to hackage, which then will have the module the function belongs to at the top of the page. For example, here is the result of searching for genericDrop and the associated hackage page.
As Nikita Volkov mentioned in his question Data.Text vs String I also wondered why I have to deal with the different String implementations type String = [Char] and Data.Text in haskell. In my code I use the pack and unpack functions really often.
My question: Is there a way to have an automatic conversion between both string types so that I can avoid writing pack and unpack so often?
In other programming languages like Python or JavaScript there is for example an automatic conversion between integers and floats if it is needed. Can I reach something like this also in haskell? I know, that the mentioned languages are weakly typed, but I heard that C++ has a similar feature.
Note: I already know the language extension {-# LANGUAGE OverloadedStrings #-}. But as I understand this language extensions just applies to strings defined as "...". I want to have an automatic conversion for strings which I got from other functions or I have as arguments in function definitions.
Extended question: Haskell. Text or Bytestring covers also the difference between Data.Text and Data.ByteString. Is there a way to have an automatic conversion between the three strings String, Data.Text and Data.ByteString?
No.
Haskell doesn't have implicit coercions for technical, philosophical, and almost religious reasons.
As a comment, converting between these representations isn't free and most people don't like the idea that you have hidden and potentially expensive computations lurking around. Additionally, with strings as lazy lists, coercing them to a Text value might not terminate.
We can convert literals to Texts automatically with OverloadedStrings by desugaring a string literal "foo" to fromString "foo" and fromString for Text just calls pack.
The question might be to ask why you're coercing so much? Is there some why do you need to unpack Text values so often? If you constantly changing them to strings it defeats the purpose a bit.
Almost Yes: Data.String.Conversions
Haskell libraries make use of different types, so there are many situations in which there is no choice but to heavily use conversion, distasteful as it is - rewriting libraries doesn't count as a real choice.
I see two concrete problems, either of which being potentially a significant problem for Haskell adoption :
coding ends up requiring specific implementation knowledge of the libraries you want to use.This is a big issue for a high-level language
performance on simple tasks is bad - which is a big issue for a generalist language.
Abstracting from the specific types
In my experience, the first problem is the time spent guessing the package name holding the right function for plumbing between libraries that basically operate on the same data.
To that problem there is a really handy solution : the Data.String.Conversions package, provided you are comfortable with UTF-8 as your default encoding.
This package provides a single cs conversion function between a number of different types.
String
Data.ByteString.ByteString
Data.ByteString.Lazy.ByteString
Data.Text.Text
Data.Text.Lazy.Text
So you just import Data.String.Conversions, and use cs which will infer the right version of the conversion function according to input and output types.
Example:
import Data.Aeson (decode)
import Data.Text (Text)
import Data.ByteString.Lazy (ByteString)
import Data.String.Conversions (cs)
decodeTextStoredJson' :: T.Text -> MyStructure
decodeTextStoredJson' x = decode (cs x) :: Maybe MyStructure
NB : In GHCi you generally do not have a context that gives the target type so you direct the conversion by explicitly stating the type of the result, like for read
let z = cs x :: ByteString
Performance and the cry for a "true" solution
I am not aware of any true solution as of yet - but we can already guess the direction
it is legitimate to require conversion because the data does not change ;
best performance is achieved by not converting data from one type to another for administrative purposes ;
coercion is evil - coercitive, even.
So the direction must be to make these types not different, i.e. to reconcile them under (or over) an archtype from which they would all derive, allowing composition of functions using different derivations, without the need to convert.
Nota : I absolutely cannot evaluate the feasability / potential drawbacks of this idea. There may be some very sound stoppers.
I just realized that I can define my own Prelude module and carefully control its exports.
Is this considered bad practice?
Advantages:
No need to repeatedly import a "Common" module in large projects.
No need to write "import Prelude hiding (catch)".
In general its a bad idea, as you end up with code written in your own idioms that isn't going to be easy to maintain by others.
To communicate with others you need a shared language of symbols. The Prelude is our core language, so if you redefine it, expect confusion.
The exception to this rule would be when developing an embedded domain-specific language. There, making a custom Prelude is entirely a good idea, and is indeed why it is possible to redefine the Prelude (and inbuilt syntax) in the first place.
By all means have your own additional modules, but don't override the Prelude.
I have been using Haskell for quite a while. The more I use it, the more I fall in love with the language. I simply cannot believe I have spent almost 15 years of my life using other languages.
However, I am slowly but steadily growing fed up with Haskell's standard libraries. My main pet peeve is the "not polymorphic enough" definitions (Prelude.map, Control.Monad.forM_, etc.). I have a lot of Haskell source code files whose first lines look like
{-# LANGUAGE NoMonomorphismRestriction #-}
module Whatever where
import Control.Monad.Error hiding (forM_, mapM_)
import Control.Monad.State hiding (forM_, mapM_)
import Data.Foldable (forM_, mapM_)
{- ... -}
In order to avoid constantly hoogling which definitions I should hide, I would like to have a single or a small amount of source code files that wrap this import boilerplate into manageable units.
So...
Has anyone else tried doing this before?
If the answer to the previous question is "Yes", have they posted the resulting boilerplate-wrapping source code files?
It is not as clear cut as you imagine it to be. I will list all the disadvantages I can think of off the top of my head:
First, there is no limit to how general these functions can get. For example, right now I am writing a library for indexed types that subsumes ordinary types. Every function you mentioned has a more general indexed equivalent. Do I expect everybody to switch to my library for everything? No.
Here's another example. The mapM function defines a higher order functor that satisfies the functor laws in the Kleisli category:
mapM return = return
mapM (f >=> g) = mapM f >=> mapM g
So I could argue that your traversable generalization is the wrong one and instead we should generalize it as just being an instance of a higher order functor class.
Also, check out the category-extras package for some examples of these higher order classes and functions which subsume all your examples.
There is also the issue of performance. Many of thesr more specialized functions have really finely tuned implementations that dramatically help performance. Sometimes classes expose ways to admit more performant versions, but sometimes they don't.
There is also the issue of typeclass overload. I actually prefer to minimize use of typeclasses unless they have sound laws derived from theory rather than convenience. Also, typeclasses generally play poorly with the monomorphism restriction and I enjoy writing functions without signatures for my application code.
There is also the issue of taste. A lot of people simply don't agree what is the best Haskell style. We still can't even agree on the Prelude. Speaking of which, there have been many attempts to write new Preludes, but nobody can agree on what is best so we all default back to the Haskell98 one anyway.
However, I think the overall spirit of improving things is good and the worst enemy of progress is satisfaction, but don't assume there will be a clear-cut right way to do everything.