Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

import Prelude by default #50

Open
gelisam opened this issue Aug 16, 2013 · 7 comments
Open

import Prelude by default #50

gelisam opened this issue Aug 16, 2013 · 7 comments
Assignees

Comments

@gelisam
Copy link
Collaborator

gelisam commented Aug 16, 2013

If the user does not mention Prelude in ~/.hawk/prelude.hs, import it unqualified.
If the user imports the Prelude unqualified, import it unqualified.
If the user imports the Prelude qualified, import it with the same qualifier.

@melrief
Copy link
Collaborator

melrief commented Aug 18, 2013

I'm testing the default import of prelude unqualified. There are many problems with list functions that doesn't work on ByteString. For instance:

{-# LANGUAGE OverloadedStrings #-}

module Main where
import qualified Data.ByteString.Lazy.Char8 as C8
import Prelude

main :: IO 
main = do
    let s = C8.pack "Foo bar"
    let w = words s
    print w

doesn't compile:

> ghc Main.hs
[1 of 1] Compiling Main             ( Main.hs, Main.o )

Main.hs:10:19:
    Couldn't match type `C8.ByteString' with `[Char]'
    Expected type: String
      Actual type: C8.ByteString
    In the first argument of `words', namely `s'
    In the expression: words s
    In an equation for `w': w = words s

and we have the same problem in Hawk:

> ps aux | hawk -m words             

Won't compile:
    Couldn't match type `Data.ByteString.Lazy.Internal.ByteString'
              with `[GHC.Types.Char]'
Expected type: Data.ByteString.Lazy.Internal.ByteString
               -> [GHC.Base.String]
  Actual type: Data.ByteString.Lazy.Internal.ByteString
               -> [Data.ByteString.Lazy.Internal.ByteString]

We should think really carefully what we want to import automatically because it can confuse the user. I don't think Prelude is the right module, we should create something ad-hoc and different from Prelude. For instance, ByteString is not a Functor while List is a Functor, so map has a different meaning:

> import qualified Prelude as P
> import qualified Data.ByteString.Lazy.Char8 as C8
> :t Prelude.map
map :: (a -> b) -> [a] -> [b]
> :t C8.map
C8.map :: (P.Char -> P.Char) -> C8.ByteString -> C8.ByteString
> P.map isSpace "f oo"
[False,True,False,False]
> C8.map isSpace $ C8.pack "f oo"

<interactive>:20:8:
    Couldn't match type `P.Bool' with `Char'
    Expected type: Char -> Char
      Actual type: Char -> P.Bool
    In the first argument of `C8.map', namely `isSpace'
    In the expression: C8.map isSpace
    In the expression: C8.map isSpace $ C8.pack "foo  bar foo bar"

@gelisam
Copy link
Collaborator Author

gelisam commented Aug 18, 2013

Well, having map not work on lists isn't ideal either. Maybe this custom module could expose a two-parameter typeclass supporting both map :: (a -> b) -> [a] -> [b] and map :: (Char -> Char) -> ByteString -> ByteString? Something like the classy prelude.

Personally, for the first release, I would just qualify ByteString with B and remind the user that all string functions must be qualified with B. We could also have T for Data.Text.

What is least confusing for the user: that strings are instances of ByteString instead of String, or that prelude functions aren't available and/or don't have the types they do in the prelude? What is the least inconvenient, remembering to add the prefix B. to all string functions, or remembering the intricacies of our custom functions?

I think the first answer to each question is slightly better, but I could easily be convinced otherwise.

@melrief
Copy link
Collaborator

melrief commented Aug 18, 2013

I agree with you. What do you think if we close this and open a new issue about the default prelude.hs to decide which modules should be imported and how?

@gelisam
Copy link
Collaborator Author

gelisam commented Aug 18, 2013

This issue is about automatically importing the prelude if it does not appear in prelude.hs, just like the Prelude is implicitly available by default in a standard Haskell program unless you explicitly discard it or import it qualified. Whether the default contents of prelude.hs should import the Prelude or not (implicitly or explicitly) is indeed a different issue. Let's open a new one for choosing the default contents, but could we please leave this one open? I was very confused when my first attempt at creating a prelude.hs containing just "rev = reverse" failed to compile.

@melrief
Copy link
Collaborator

melrief commented Aug 18, 2013

That's because of the NoImplicitPrelude extension that I set on hint. The idea was to give to the user the power to change everything, so if the user doesn't import Prelude then he doesn't want it. That's probably different from what we want and it should be fixed.
I think we should import Prelude every time as you said unless the user specifies the NoImplicitPrelude extension. I leave this open, you are right.

p.s. now that we have the source parser we probably can extract the extensions and set them in hint

@gelisam
Copy link
Collaborator Author

gelisam commented Aug 18, 2013

Letting the user decide if he wants NoImplicitPrelude? Good idea, I didn't think of that! Doing so in a more general way by accepting any extension and passing them along to hint? Absolutely brilliant!

melrief added a commit that referenced this issue Aug 18, 2013
@melrief
Copy link
Collaborator

melrief commented Aug 18, 2013

I let you close the issue. As side note I kept the NoImplicitPrelude extension and I import it manually if it is missing. I will remove the extension when we implement the system to load the user extensions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants