hawk icon indicating copy to clipboard operation
hawk copied to clipboard

import Prelude by default

Open gelisam opened this issue 11 years ago • 7 comments

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.

gelisam avatar Aug 16 '13 01:08 gelisam

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"

melrief avatar Aug 18 '13 10:08 melrief

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.

gelisam avatar Aug 18 '13 15:08 gelisam

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?

melrief avatar Aug 18 '13 17:08 melrief

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.

gelisam avatar Aug 18 '13 17:08 gelisam

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

melrief avatar Aug 18 '13 17:08 melrief

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!

gelisam avatar Aug 18 '13 18:08 gelisam

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.

melrief avatar Aug 18 '13 21:08 melrief