[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Haskell comments on modules
From: Professor Simon Peyton-Jones <simonpj@cs.glasgow.ac.uk>
Date: Tue, 11 Sep 90 21:14:55 BST
To: augustss, haskell@cs.glasgow.ac.uk, simonpj@cs.glasgow.ac.uk
Subject: Re: Haskell comments on modules
Sender: haskell-request@cs.glasgow.ac.uk
Some replies to Lennart's excellent questions. Thank you Lennart for
taking the trouble to pose them.
| Is the interface on page 43 correct? I quote from page 44:
|
| "A module may export a value whose typing involves a type and/or class
| that is not exported. Nevertheless, it is still required that the
| interface contain the import declaration required to give the original
| name of the type or class."
|
| As you can see the interface contains Num and Bool without stating
| where they came from. I presume that the rule above does not apply
| to types/classes from the standard prelude.
|
Yes, this proviso should be in there.
| Turning to page 46, what is a correct interface for module B?
| Is this correct?
| -- 2
| interface B where {
| import A(Tree);
| leaves :: (Tree a) -> [a]
| }
This is right. The import of Tree from A establishes its original name.
Any module importing B had better import Tree from A too.
| Even nore problematic, what is a correct interface for C?
| This seems the most likely:
| interface C where {
| import A(Tree(..)) renaming (Tree to Arbre, Leaf to Feuille, Branch to Branche);
| import A(depth) renaming (depth to fond);
| import B(leaves) renaming (leaves to feuilles);
| data Arbre b = Feuille b | Branche (Arbre b) (Arbre b);
| fond :: (Num b, Ord b) => (Arbre a) -> b,
| feuilles :: (Tree a) -> [a]
| ^^^^^^^^
| }
| Notice that Tree has not been renamed for feuilles, but nothing is
| said about that on importing leaves. You could argue that it should
| be Arbre anyway, but what if module C imports module A once more this
| time translating everything to German, what should appear for feuilles then?
Well, Tree a must be wrong, since it is not in scope; it has been renamed
to Arbre by the import. If you imported it twice, then there are two
names for the same thing, a question John Peterson has been addressing
on this mailing list recently.
I think that if something has two names in an interface you should be
allowed to use either. Interfaces are not uniquely defined.
| consider the following module
|
| ----
| module Test(C(..)) where
| class C a where
| op : a
|
| data T = A | B
|
| instance C T where
| op = A
| ---
|
| What should the interface be?
| ---
| interface Test where
| class C a where
| op : a
|
| instance C T
| ---
|
| Is this valid? If it is, it means that no other module can use this
| interface since it contains an undefined identifier T.
|
| I suggest that instances should be only be exported if both the type
| and class are externally visible (all the oher condiions should still apply
| as well).
Sigh. We did consider this case, and (I think) decided to live with
the infelicity that indeed C cannot usefully be imported from Test
because T couldn't be in scope.
We considered:
- don't export instance decls for types or classes defined
in the module and not exported
- don't "activate" a C-T instance decl unless both
C and T are in scope.
The present choice is not obviously the optimum, but it means we have
one less "except if.." clause in the report. Better solutions welcomed.
| How are the type variables in an instance declration scoped?
| Consider
| instance C (T a) where
| op = ... (e :: a) ...
|
| Is the a in 'e :: a' the same as the a in 'C (T a)'?
| I hope it is. It makes it harder to implement, but it
| makes certain instance declarations much easier to write.
Presently, type signatures are universally quantified over all their
free variables (p16, p31), except in the signatures given in class decls.
Your proposal would add a new exception, but would not be hard to implement
I think. In Dagstuhl you gave a rather nice example of the use of such
scoping; can you repeat it please because I have forgotten.
Simon