Hi All,
I have been following the Advent-of-Code using Rust, and one thing that really hit me is how well integrated the namespace system is compared to the one we have in Haskell. So, I was thinking about how namespaces could be implemented in Haskell, and I’m not sure it’s good enough to create a GHC proposal, so I would like your feedback.
First, why not just use modules? Well, modules are currently being tied to specific files, and often we want our namespaces to be more particular.
I’m going to use the X::a
notation to indicate namespaces, we can differentiate it from types in the same way as we do for modules M.a
. I guess, this will be controversial.
We can add functions and variables to namespace like so:
namespace Entry where
empty :: Entry
empty = ...
toText :: Entry -> Text
toText = ...
To use a namespace variable, you can refer to it directly:
main = do
putStrLn (Entry::toText Entry::empty)
or you can open it:
main = do
use Entry::*
putStrLn (toText empty)
which is equivalent to:
main = do
let toText = Entry::toText
empty = Entry::empty
putStrLn (toText empty)
*Benefits using namespaces, … *
-
we can make tooling give better code predictions. For example, if we type
Entry::
the IDE would know there is only two interesting functions to report. -
we could prevent name collisions on records in a structured way. In another extension, we could make record functions be automatically assigned to the namespace of the record.
data Entry = Entry { date :: Date, mesg :: Text } data Error = Error { mesg :: Text } --- We can differentiate between them with toTextBoth entry error = Entry::mesg entry <> Error::mesg error
-
we could encapsulate free orphan instances: an instance is only considered if the name space is open.
namespace Danger where instance Show Bool where show True = "False" show False = "True"
If you then need this orphan instance, you can open the namespace, as we do with modules, however, we can limit the scope and namespaces do not inherit each others variables.
main = do do use Danger::() print True -- prints False print True -- prints True, again
-
we could add tests in the same module as our code, but not pollute the namespace.
add :: Int -> Int -> Int add a b = a + b namespace Test where addShouldBeCommuative a b = add a b === add b a
Questions
-
Should namespaces be open, so that you can redefine names of spaces later in the file or in other modules?
-
Should namespaces be nested, so that you can define sub namespaces?
I’m sure how hard it would be to introduce this to GHC, some of the changes seems like it’s only about names, which could be fixed with a weird naming scheme `, others are a little more involved.
So could/should we add namespaces to Haskell?