caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Arthur Wendling <art.wendling@gmail.com>
To: Simon Cruanes <simon.cruanes.2007@m4x.org>
Cc: Anthony Tavener <anthony.tavener@gmail.com>,
	Gabriel Scherer <gabriel.scherer@gmail.com>,
	 "caml-list@inria.fr" <caml-list@inria.fr>
Subject: Re: [Caml-list] destructive local opens
Date: Wed, 19 Aug 2015 18:42:49 +0200	[thread overview]
Message-ID: <CADfBENnyf-TyqydWJ_ZnjB5T5HnhZqeWQfAf5TvbEi+2gC5UsQ@mail.gmail.com> (raw)
In-Reply-To: <D7CDD808-BC13-4D77-9EDD-D9F450391993@m4x.org>

[-- Attachment #1: Type: text/plain, Size: 10464 bytes --]

While we do not have "unlet", we do have the ability to restrict a module
definition by subtyping it to a stricter signature, which achieves the
inverse effect:

    module V2_add = (V2 : sig val ( + ) : V2.t -> V2.t -> V2.t end)
    V2.(ox + oy)      -- shadow ox, oy?
    V2_add.(ox + oy)  -- only +

We probably don't use the restricted signatures more often because it's
quite verbose: we have to repeat the types of each binding, and we can't
use the syntax (M : ...) everywhere. Those are syntax errors for example:

    open (V2 : ...)           -- but include (V2 : ...) works!
    (V2 : ...).( ox + oy )

So we have to go through a named module, and it gets horribly verbose.
Maybe we can steal the Haskell solution here, where the tendency is to list
every imported binding:

    import V2 (ox, oy, ...)   -- note the lack of types

This is (sometimes) nicer for a reader, since the origin of a name is
directly visible, and it's explicit that we only use a subset of each
opened module -- so that you know which definitions of V2 you have to check.

Now, let's imagine that we had such a light syntax, maybe:

    (M with val ox, oy, (+), ...) -- for the vague resemblance with
existing syntax
    (M for ox, oy, ...)           -- looks lighter, but the keyword is
unfortunate

then we could write this explicit form, which should not deserve any
warning:

    let ox = (V2 for dot, ( * )).((dot v ox) * ox) in
    (V2 for ( * ), ( + )).(3 * ox + oy)

    let open (V2 for dot, ( + ), ( * )) in
    let ox = (dot v ox) * ox in
    3 * ox + oy

Sure, it's a lot more explicit than the other alternatives proposed in this
thread, but it might also be beneficial outside of the M.( ... ) sugar
situation.
Random clarifications:
- (M for x, ...) would be a shortcut for (M : sig val x : (module type of
M).x ... end), which isn't even valid.
- We would probably want (M for type t) too, but constructors and record
fields are problematic, since we have to import them all (?).
- (M for x as y) could be a nice extension for renaming and not shadow x.
- Bonus: open (M for x) can correctly report M.x as missing if it has been
renamed.

Also, while I would appreciate "unlet x in", I don't think that we want to
be negatively informative when it comes to opening a module: (M without x)
isn't failproof regarding what remains; and the proposed annotation
[@shadow x] looks good enough for the purpose of scripting the warning
heuristic.

On Wed, Aug 19, 2015 at 5:55 PM, Simon Cruanes <simon.cruanes.2007@m4x.org>
wrote:

> This whole thread makes me wonder whether local opens are worth it. I
> don't like global open (at all), and shadowing is harmful even in smaller
> scopes. Local open seems to be used for DSL that have a lot of infix
> operators (maths, etc.) as demonstrated by the proposal of new warnings and
> syntax about shadowing of infix operators.
>
> If modules have short names (Z, Q from Zarith come to mind, but
> module-aliasing your favorite monad to "M" would do too), would M.+ be a
> reasonable infix operator? I would be ready to have slightly more verbose
> calls to M.>>= if it removes ambiguity and potential shadowing bugs. Of
> course I don't know if this is compatible with the current syntax.
>
>
> Le 19 août 2015 00:26:00 UTC+02:00, Anthony Tavener <
> anthony.tavener@gmail.com> a écrit :
>>
>> (TL;DR: I commonly want to specify paths -uniquely- for identifiers in
>> local
>> scopes (function, module) which have no means to do this.)
>>
>> As I run into this yet again, moments ago...
>>
>> I do often want the ability to be clear that something is not to be
>> shadowed
>> by the opened scope... to specify it's from the local (usually function)
>> scope.
>> Part of the reason is for code clarity, but also to safeguard against
>> possible
>> later changes in the *opened* module (introducing the same identifier).
>>
>>   let init flags =
>>     M.(init (flag1 + flag2 + flags)) (* flags is intended to be 'local',
>> but it could be shadowed by a value in M *)
>>
>> Where M provides 'init', 'flag1', 'flag2', and '+', but 'flags' is in the
>> local (function) context. When I do this I try to think of a way to make
>> it
>> self evident that 'flags' is not from M, but there is no way. Aside from
>> bringing it outside the local-open, but then it's more difficult to build
>> an expression.
>>
>> Vimscript might be one of the worst languages to use as a reference, but
>> this
>> issue does bring to mind the scope prefixes...
>>
>>   let init flags =
>>     M.(init (flag1 + flag2 + l:flags)) (* illustrative -- not a proposal!
>> *)
>>
>> I sometimes consider using naming conventions, but I don't want to
>> explicitly
>> make function arguments something like l_flags, l_point, etc. That would
>> be a
>> horrible widespread style, and doesn't work nicely with named arguments.
>> Plus, changing names to do this seems wrong -- it's at the access site
>> where
>> you want to disambiguate, which always leads me to think some sigil or
>> prefix.
>>
>> There was an earlier sidetrack which went with ^ as an "unopen" prefix.
>> At first,
>> my interest was piqued. Naturally, the issue of recursive unopen came
>> up...
>>
>> In response, Gabriel wisely remarked:
>>
>>  "It is remarkable that programming languages have avoided introducing
>>   explicit weakening (the popping of a symbol out of scope) for now, and
>>   I think it is a property that should be preserved. We're not yet ready
>>   to go there."
>>
>> Good advice when the thread was spinning out of control and probably not
>> going
>> to settle on anything realistic or favorable. Even though there might be
>> merit
>> in pursuing fine-grained scope-popping as its own topic.
>>
>> I think there is a simpler gain to be had from the idea of being able to
>> specify
>> the path of the current context. "Current context" would need to be
>> something sensible, and I'm not sure yet what would be best, as there is a
>> related issue I encounter commonly:
>>
>> A way to specify the path of the current module.
>>
>> There is no way to do this, right? If I'm in "a.ml", I can't refer to
>> A.identifier, and there is no other way to uniquely specify the path to
>> what
>> *will become* A.identifier? As the bare "identifier" can be shadowed by
>> any
>> modules opened afterward. Unlike the general "scope-popping", there is
>> also
>> a common language feature like this: self or this.
>>
>> I usually want to be explicit with module paths, especially if I am using
>> an
>> "identifier" which could reasonably be expected to exist now or later in
>> the
>> other modules being used. I do keep opens to a minimum, but often an
>> entire
>> expression will be in a local open (to bring in operators), and there,
>> again... I would like that clarity, and safeguard against changes which
>> might
>> happen in the other modules, leading to suprises or need to change *this*
>> module for no good reason other than a naming conflict which ideally can
>> be
>> prepared against.
>>
>> Has there been any discussion about referring to the local module? My
>> guess is
>> that it might be a mild enough problem to not warrant any proposed
>> solutions.
>> But if there are ideas, maybe the same thing or something similar can also
>> apply to this problem of "escaping" a local open? They are very similar,
>> but
>> one is module-scope, while I think the other would be function-scope
>> (though
>> module-scope might imply the "right thing" anyway)... I'm not certain, as
>> haven't been keeping track of the cases I encounter, and others might have
>> different use-cases.
>>
>>
>> On Tue, Aug 18, 2015 at 7:00 AM, Gabriel Scherer <
>> gabriel.scherer@gmail.com> wrote:
>>
>>> Note that the dual feature does not exist for variant constructors,
>>> because it is easy to define only on the constructor at the toplevel of the
>>> pattern, and nested patterns get us in muddy waters.
>>>
>>> On Tue, Aug 18, 2015 at 2:52 PM, David Allsopp <dra-news@metastack.com>
>>> wrote:
>>>
>>>> Goswin von Brederlow wrote:
>>>> > On Fri, Aug 14, 2015 at 01:28:50PM +0200, Drup wrote:
>>>> > >
>>>> > > >You can't qualifylocal values or values of the surrounding module
>>>> so
>>>> > > >that is a no go.
>>>> > > >
>>>> > > >I also often use local open to access records, as in:
>>>> > > >
>>>> > > >let r = M.({ x = 1; y; z = depth; }) in
>>>> > >
>>>> > > You can avoid the local open altogether and write it like that:
>>>> > >
>>>> > >     let r = {M. x = 1; y; z = depth } in
>>>> > >
>>>> > > It's even shorter.
>>>> >
>>>> > That only works because newer ocaml disambiguises (is that a word?)
>>>> record
>>>> > So it's implicitly using M.y = y and M.z = depth.
>>>> > labels when it determines the record type from the first label, right?
>>>>
>>>> Only since you ask: "disambiguates" :o) That said, it's quite common to
>>>> see words like "disambiguises" being invented by Americans!
>>>>
>>>> But this isn't related to the disambiguation features of OCaml 4.01+.
>>>> Those allow you to write things like:
>>>>
>>>> type t = {x : int}
>>>> type u = {x : int; y : string}
>>>>
>>>> let foo = {x = 1}
>>>> let bar = {x = 42; y = ""}
>>>>
>>>> This is actually a much older notation added in OCaml 3.08. Prior to
>>>> that, if you hadn't opened a module you had to qualify each label:
>>>>
>>>> {M.x = 1; M.y = y; M.z = depth}
>>>>
>>>> but this was "silly", since it's not possible to use non-equivalent
>>>> module paths for labels, so OCaml 3.08 changed it so that you only needed
>>>> to put the module path on one label (and it doesn't have to be the first
>>>> one, it's just a bit weird to put it in the middle!).
>>>>
>>>> OCaml 3.12 added, amongst other record-related goodies, the shorthand
>>>> {y} to mean {y = y}. So while you can use local open as you're using it,
>>>> you've been able to do it as a totally unambiguous language feature for
>>>> quite some time.
>>>>
>>>>
>>>> David
>>>>
>>>>
>>>> --
>>>> Caml-list mailing list.  Subscription management and archives:
>>>> https://sympa.inria.fr/sympa/arc/caml-list
>>>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>>>> Bug reports: http://caml.inria.fr/bin/caml-bugs
>>>>
>>>
>>>
>>
> --
> Simon
>

[-- Attachment #2: Type: text/html, Size: 12958 bytes --]

  reply	other threads:[~2015-08-19 16:42 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-03 13:39 Nils Becker
2015-08-03 13:43 ` Thomas Refis
2015-08-03 13:45 ` Daniel Bünzli
2015-08-03 13:47   ` Daniel Bünzli
     [not found]     ` <55BF75F6.1040006@bioquant.uni-heidelberg.de>
2015-08-03 14:24       ` Daniel Bünzli
2015-08-03 14:37         ` Gabriel Scherer
2015-08-03 14:43           ` Daniel Bünzli
2015-08-03 15:10           ` octachron
2015-08-03 15:22             ` Daniel Bünzli
2015-08-03 16:13               ` octachron
2015-08-03 16:51                 ` Daniel Bünzli
2015-08-03 17:18                   ` Hendrik Boom
2015-08-03 17:59                   ` octachron
2015-08-06 13:23                     ` RE : " moreno pedro
2015-08-04  6:51         ` Petter Urkedal
2015-08-04  9:33           ` Goswin von Brederlow
2015-08-05  6:40             ` Petter A. Urkedal
2015-08-05 10:16               ` David Allsopp
2015-08-06  9:35               ` Goswin von Brederlow
2015-08-04 13:50           ` Hendrik Boom
2015-08-04  9:26         ` Goswin von Brederlow
2015-08-04  9:38           ` Daniel Bünzli
2015-08-04 12:26             ` vrotaru.md
2015-08-04 13:12               ` David Allsopp
2015-08-04 13:17                 ` Jeremy Yallop
2015-08-04 13:54                   ` vrotaru.md
2015-08-04 15:25                   ` Drup
2015-08-04 22:22                     ` vrotaru.md
2015-08-04 22:55                       ` Hendrik Boom
2015-08-05  4:52                         ` Gabriel Scherer
2015-08-04 13:14               ` Ivan Gotovchits
2015-08-14 10:55                 ` Goswin von Brederlow
2015-08-14 11:28                   ` Drup
2015-08-18 11:11                     ` Goswin von Brederlow
2015-08-18 12:52                       ` David Allsopp
2015-08-18 13:00                         ` Gabriel Scherer
2015-08-18 22:26                           ` Anthony Tavener
2015-08-19 13:55                             ` Oleg
2015-08-19 14:13                               ` John Whitington
2015-08-19 15:47                                 ` Hendrik Boom
2015-08-19 15:52                             ` Hendrik Boom
2015-08-19 18:09                               ` Anthony Tavener
2015-08-19 15:55                             ` Simon Cruanes
2015-08-19 16:42                               ` Arthur Wendling [this message]
2015-08-19 21:15                               ` octachron
2015-08-20  8:06                                 ` Romain Bardou
2015-08-20 17:03                                   ` Yotam Barnoy
2015-08-20 19:19                                     ` Erkki Seppala
2015-08-06  9:23               ` Goswin von Brederlow
2015-08-06  9:21             ` Goswin von Brederlow
2015-08-06 10:19               ` Daniel Bünzli
2015-08-06 13:36                 ` Hendrik Boom
2015-08-14 10:57                   ` Goswin von Brederlow
2015-08-17 10:17 Nils Becker
2015-08-17 14:26 ` Gabriel Scherer
2015-08-17 15:11   ` Nils Becker
2015-08-17 15:17     ` Drup
2015-08-17 15:18     ` Gabriel Scherer
2015-08-17 18:31       ` Hendrik Boom

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CADfBENnyf-TyqydWJ_ZnjB5T5HnhZqeWQfAf5TvbEi+2gC5UsQ@mail.gmail.com \
    --to=art.wendling@gmail.com \
    --cc=anthony.tavener@gmail.com \
    --cc=caml-list@inria.fr \
    --cc=gabriel.scherer@gmail.com \
    --cc=simon.cruanes.2007@m4x.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).