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

Support include for libraries, to "merge" several libraries into one single namespace #691

Closed
tahina-pro opened this issue Sep 23, 2016 · 9 comments

Comments

@tahina-pro
Copy link
Member

tahina-pro commented Sep 23, 2016

Consider a series of libraries pertaining to a data structure, e.g. FStar.Seq and FStar.SeqProperties for finite sequences. Then, to use finite sequences in their programs, end users would have to explicitly import all libraries through:

open FStar.Seq
open FStar.SeqProperties

Ideally, we would like to provide the user with a single library which would be enough for them to import, regardless of how and why the other underlying libraries are organized.
In our example, we would rename FStar.Seq into FStar.SeqBase, and we would like to provide the user with a single FStar.Seq library so that open FStar.Seq would automatically import FStar.SeqBase and FStar.SeqProperties. The contents of FStar.Seq would be something like:

module FStar.Seq
include FStar.SeqBase
include FStar.SeqProperties

This solution would be enough for the user to import all definitions of FStar.SeqBase and FStar.SeqProperties into the unqualified namespace.
(It would be actually similar to Export in Coq, to this respect, see for instance ZArith in the Coq standard library for mathematical integers.)

However, what if the user wants to use both finite sequences and lists in their programs? In particular, what if the user wants to use length and append from both FStar.Seq and FStar.List.Tot, and their associated lemmas? Then, the user will need to explicitly qualify their uses of append with correct namespaces.
In this case, the user will need to figure out that the append related to lists is actually defined in FStar.List.Tot, which is vulnerable to any refactoring of the underlying list libraries.

Ideally we would like to define FStar.List so that the user can access the list-related append using FStar.List.append, regardless of which underlying library it is actually defined in.

BEGIN DIGRESSION
In Coq, this is possible thanks to nested modules. For instance, for mathematical integers, one can do Import ZArith which provides the user with a Z namespace giving access to all operators and lemmas related to mathematical integers, such as Z.add (addition) and Z.add_0_r (the fact that x+0=x.)
In fact, this Z namespace is made of two modules called Z, one defined in BinIntDef and providing Z.add, and another defined in BinInt and providing Z.add_0_r. BinIntDef and BinInt are both exported by ZArith.
Now, if the user only wants to use mathematical integers, they can Import ZArith and Import Z once and get add and add_0_r both in the unqualified namespace, since BinInt.Z has Include BinIntDef.Z.
END DIGRESSION

Of course this is not currently possible in F*. So, we would like to have the proposed include mechanism take care of this namespace issue as well, so that, renaming FStar.List into Fstar.ListBase
and defining FStar.List as:

module FStar.List
include FStar.List.Tot
include FStar.ListBase
include FStar.ListProperties

@tahina-pro
Copy link
Member Author

The following question may need to be spun off as a separate issue at some point: should we shift the focus of the F* standard list library from effectful to total functions? In other words, instead of having FStar.List for effectful functions and FStar.List.Tot for total functions:

  • should we instead have FStar.List for total functions and FStar.List.Effectful for effectful functions?
  • with the above namespace proposal, should we still have FStar.List.Tot exported by FStar.List, but not have effectful functions exported by FStar.List at all?
  • or, on the contrary, should we have both effectful and total functions exported by FStar.List, and if so, which ones should we allow to shadow the others in the FStar.List namespace?

@msprotz
Copy link
Collaborator

msprotz commented Sep 24, 2016

Isn't it just a matter of having an include directive, where module FStar.List is just the inclusion of several other modules? This scenario may be supported by the "cheap functor" proposal I had a while ago... but maybe a proper export directive would be more appropriate, indeed.

@nikswamy
Copy link
Collaborator

I was expecting that this could be supported purely as a namespacing mechanism. If we have module A export B, then resolving A.f while would transitively search in the namespace of B.

tahina-pro added a commit that referenced this issue Nov 8, 2016
The goal of this syntax change is to ensure that, for any name
of the form Namespace.ident or Namespace.Name, the Namespace part
is always a valid module name (except if Namespace.Name is itself
the name of a module.)

So far, this property was not holding for the following two
cases:

- many occurrences of Some.v to project the formal parameter v
  of an option value that is known to be Some;

  Formally, whenever an inductive type t is defined:

  type t = | Datacon : param: u -> t | ...

  then, for any value vt : t {is_Datacon v} , it is valid to
  use (Datacon.param vt), of type u, to extract the value of
  the formal parameter.

  This introduces a spurious dependency on a hypothetical
  module called Some (and a clash if any Some module is
  reachable from open namespaces.)

- STATE.pre, STATE.post, and other effect members, similarly
  introducing spurious dependencies on a hypothetical STATE
  module.

As mentioned, the main consequence of those data constructor and
effect namespaces not being true modules are spurious dependency
generation and potential clashes with modules. I claim that this
current situation also gets in the way of any improvement on
name resolution, e.g. potential support for `include', currently
being discussed as `export' at:

#691

Thus, we need to introduce new syntax to change these
data constructor projector and effect member notations.
While I arbitrarily chose .. for testing purposes, discussions
about the final concrete syntax are still ongoing at:

http://doodle.com/poll/enadrtwqb6vhu2tr

However, independently of the actual choice for concrete syntax,
this syntax change implies the following deeper changes:

1. The projector for a formal parameter of a data constructor
   has been renamed, both internally and on the extracted code.

   Previously, Datacon.param was added as a fully qualified
   name for the corresponding projector. To avoid clashes with
   name resolution in open namespaces, it is now renamed as
   __proj__Datacon__item__param

   We could have used the reserved prefix uu___ (defined as
   reserved_prefix in src/basic/ident.fs), but using such
   prefix actually makes the verification of
   examples/preorders/MRefHeap.fst fail when replaying hints,
   for an unknown reason so far.

2. The fields of a record have been renamed similarly in
   extracted code.

   This is for two reasons. First, a record field is treated in
   the same way as a formal parameter of a data constructor,
   for internal purposes. In particular, given the following
   record type:

   type reco = { field: unit; ... }

   the elaborator actually turned any field access of the form
   expr.field intro (Mk_reco.field expr) where Mk_reco is the
   name of the data constructor created by transforming the
   record type into an inductive type, and so Mk_reco.field was
   exactly the data constructor projector for the 'field'
   formal parameter of the Mk_reco (unique) data constructor.
   We preserve this elaboration as a projector, but now using
   the new projector name instead.

   However, the second reason is that, since such projector
   calls are turned back to field accesses in extracted ML code,
   we do not want to rely on the extracted language's shadowing
   mechanism (for two different record types in the same module,
   each of which having a field with the same name in both),
   and so we use our field renaming as a way to resolve any such
   shadowing in advance.

3. The fields (pre, post, reflect, return, bind, and actions)
   of an effect have been renamed similarly, both internally
   and in extracted code.

   In this process, we took extra care to preserve the monad scope
   while defining the members and actions of an effect, in such
   a way that those names need not be qualified by the effect name
   while being defined. However, once defined, such a member is
   now required to be qualified with its MonadName.. instead of
   MonadName.  In particular, this new mechanism now forbids
   `open Monad' ---opening the namespace of a monad to access its
   members through unqualified names outside of the monad
   definition. Fortunately, this happens nowhere in any examples.

The main purpose of these renamings is to guarantee that, for any
global definition whose fully qualified name is of the shape
Namespace.ident, Namespace is now always a valid module, which
was not the case until now for data constructor projectors and
effect fields.
@tahina-pro
Copy link
Member Author

tahina-pro commented Dec 6, 2016

export renamed into include, since the proposed feature is similar to OCaml's include

@tahina-pro tahina-pro changed the title Support export for libraries, to "merge" several libraries into one single namespace Support include for libraries, to "merge" several libraries into one single namespace Dec 6, 2016
tahina-pro added a commit that referenced this issue Dec 6, 2016
@tahina-pro
Copy link
Member Author

In fact, the new branch taramana_include that I just pushed deprecates the old branch taramana_export, thanks to the name resolution improvements merged in pull request #772 .

@tahina-pro
Copy link
Member Author

tahina-pro commented Dec 6, 2016

The branch taramana_include_seq, descending from taramana_include, illustrates the use of include with FStar.Seq, exactly as mentioned in this issue:

module FStar.Seq
include FStar.Seq.Base
include FStar.Seq.Properties

and all client code only uses FStar.Seq, no longer explicitly mentioning the former FStar.SeqProperties module.

@catalin-hritcu
Copy link
Member

@tahina-pro So can this be closed now?

@tahina-pro
Copy link
Member Author

tahina-pro commented Apr 9, 2017

Done for sequences (see above) and also for lists (FStar.List.Tot includes FStar.List.Tot.Base and FStar.List.Tot.Properties) Both merged into master.

Are there any further instances in the standard library where include might be desirable?

@wintersteiger
Copy link

Closing this as suggested by @catalin-hritcu and now follow-up on @tahina-pro's question for further instances.

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

5 participants