-
Notifications
You must be signed in to change notification settings - Fork 8
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
Implicit scope #46
base: modular-implicits
Are you sure you want to change the base?
Implicit scope #46
Conversation
I like this: resolving instances by type and adding/removing them by path seems like the right approach. Some of the behaviour around implicit Foo.Bar
implicit -Foo.Bar (* rather than "explicit Foo.Bar" *)
let- implicit IntOrd in (* rather than "let explicit IntOrd" *)
let implicit IntOrdRev (I'm not suggesting this concrete syntax, but I hope the idea is clear.) Attaching the deletion notation to the binding keyword rather than introducing a separate keyword would make it easier to extend OCaml in a uniform way if we wanted to add similar operations to other environments. |
I like this too. I am not sure to understand the purpose of |
I like the include implicit Foo syntax. Is there an alternative like |
Yes something like that might be better, the overloading of
To be clear module F {X : S} (Y : T with type t = S.t)= ...
module M = F(N) might work. You could easily extend that to supporting a general "find a module of the right type and use it here" syntax, like: module X : sig type t = int val x : t -> string end = ? Which would also naturally extend to forcing an implicit application whilst still looking up the module implicitly: let f {X : S} : X.t = ...
let foo : int = f {?} You could then extend the idea further with let foo : int = f {M.?} This might be quite useful, but I'm not really proposing it at this stage. |
|
This patch is an extension of #28. It essentially adds a separate notion of implicit scope for looking up implicit modules and functors, rather than piggybacking on the ordinary scope.
Implicit scope
OCaml's ordinary scope can be thought of as a set of identifiers, from which references are looked up. When a new identifier is defined, identifiers with the same name are removed from the set, and the new identifier is added.
Similarly, the implicit scope is a set of paths from which implicit modules are looked up. Since the lookup is by type, shadowing would ideally be done by type. However, the relationship between paths and the types that they cover is complex: depending on the other paths in scope and how types have been abstracted. This makes direct type-based shadowing too difficult to reason about. So instead we use explicit weakening, separating the removal of paths from scope from the addition of new paths to the scope.
Paths can be added using the syntax:
the previous syntax:
is now short-hand for:
Paths can be removed from the implicit scope using:
There are also corresponding local versions:
Module aliases
Since aliased module should ideally be interchangable, all module aliases are fully normalized before being added or removed from the implicit scope, so that:
will result in no overall change to the implicit scope.
Modules and open
Modules can be thought of as capturing a change in the ordinary scope. When projecting from a module the members are looked up in the scope which results from applying this change to the empty environment. When opening a module this change is applied to the current environment.
This is the approach we take with the implicit scope.
implicit
andexplicit
declarations are components of modules and when a module is opened they are applied in order to the current scope. This maintains the ability of opening modules to completely change the environment -- the classic example beingopen Core.Std
switching the entire standard library.Whilst there is not currently an equivalent to projecting the implicit scope, with implicit modules one could envisage a syntax like
M.?
to look up a module using the implicit scope ofM
.Module inclusion
When checking inclusion between modules each implicit/explicit definition in the output must be matched by an implicit/explicit definition for the same path (or an alias of it) in the input. Module aliases mean that we cannot know which implicit and explicit definitions would shadow each other. This means that all implicit definitions in the output must be in the same order, relative to the explicit definitions, as in the input -- and vice versa for explicit definitions. Implcit definitions may still be reordered relative to other implicit definitions, and likewise for explicit definitions. So:
is fine, but:
is not.
Implicit include
We also add a specialised form of
include
:which includes only the implicit definitions in
Foo
. (There is currently a bug in this caused by a bug in how modules are strengthened on the version of OCaml we forked from, when we rebase to trunk it will go away).