[m-rev.] for post-commit review: better diagnostic for missing higher order insts

Peter Wang novalazy at gmail.com
Wed Jul 26 15:42:53 AEST 2023


On Tue, 25 Jul 2023 20:15:28 +1000 "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:
> 
> On 2023-07-25 07:10 +02:00 CEST, "Peter Wang" <novalazy at gmail.com> wrote:
> > On Tue, 25 Jul 2023 07:35:35 +1000 "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:

> I just noticed this mode:
> 
> :- mode foldl(in(pred(in, di, uo) is semidet), in, di, uo) is semidet.
> 
> How useful can this be if the failure of any invocation of the predicate
> destroys the accumulator without the possibility of getting it back
> on backtracking?

The log message for commit 22a38ec1f says it was
"required by an experimental branch of G12."

> >> + at footnote{If there is a single inst or a single mode
> >> +that all instances of a given type are expected to use,
> >> +programmers will often give that inst or mode
> >> +the same name as the name of the type.
> >> +The compiler looks up names in its type table when it expects a type,
> >> +in its inst table when it expects an inst,
> >> +and in its mode table when it expects a mode,
> >> +so this does not confuse the compiler.
> >> +However, this practice @emph{can} confuse Mercury programmers
> >> +who (a) do not know this fact, or (b) are not familiar with this convention.}
> > 
> > I'm not sure we should encourage the use of trivial mode definitions.
> > I think writing a mode with in() or out() around a named inst is
> > clearer, and convenient enough.
> 
> Agreed. However, the reference manual must explain the constructs,
> because people may come across such mode definitions written by
> other people.

Right.

> Would deleting the "single mode" part of the footnote, keeping
> only the "single type" and "single inst" parts, work for you?
> Or do you think we need to add some explicit recommendation
> against mode definitions that are there just to avoid in/1 or out/1
> wrappers?
> 

The reference manual should avoid talking about the internal workings of
the compiler. I've included my suggestion for an explicit recommendation
below.

> >> + at example
> >> +:- mode foldl(pred(in, in, out) is det, in, in, out) is det.
> >> + at end example
> >> +
> >> + at noindent
> >> +and is actually written in the source code like this.
> >> + at c ZZZ *Should* it be written like that?
> >> + at c Arguably, it makes the code harder to read for novices.
> >> +
> > 
> > Yes, I think so. The fact that (pred(in, in, out) is det)
> > can both be an inst or a mode could be a source of confusion,
> > and it's only slightly more convenient than using the in() wrapper.
> 
> Are you saying "yes" to "Should it be written in the source code like this",
> or to "makes it harder to read"? The previous question is the former,
> but what follows "yes" suggests the latter.

"Yes", I agree that it makes it harder harder to read.

> 
> > We might want to remove the builtin higher-order modes eventually.
> > I will admit it is tempting to use them to make a predicate's mode
> > declarations align with the type declaration...
> 
> I could modify parse_higher_order_mode to return an error indication,
> instead of the parsed higher order mode, if an option is set. That would
> allow us to replace all the uses of this shortcut in the library, and therefore
> in the library manual. Would that be useful?
> 

Let's hear what other people think.

> >> + at c ZZZ can you omit the in(...) wrapper around named insts?
> >> + at c Answer: NO. it is not even true of the inst is an inst name that expands
> >> + at c to a higher order inst, rather than being an *explicit* higher order inst.
> >> + at c ZZZ Next question: *why* is the answer NO?
> > 
> > My understanding is that, by design, the syntax of a builtin
> > higher-order mode makes them look very much like (i.e. exactly like)
> > a higher-order inst. But an inst is an inst, and a mode is a mode.
> > The compiler isn't "expecting to find a mode, but finding an inst",
> > it's just "expecting to find a mode".
> 
> I agree that is how it looks like to the compiler. I don't think that is
> the best way to explain things to readers of the manual.
> 

What you have now is this:

    In those parts of these declarations where the compiler expects to
    find a mode, if it finds an inst instead, it implicitly inserts the
    'in()' around that inst.

But that explanation leads to the question that you marked with ZZZ:

    If the compiler will implicitly insert in() around the inst,
    then why doesn't this work:

	:- mode foldl(named_inst, in, in, out) is det.

The following changes are for review.

Peter


diff --git a/doc/reference_manual.texi b/doc/reference_manual.texi
index fb00efe00..d14c4ee3e 100644
--- a/doc/reference_manual.texi
+++ b/doc/reference_manual.texi
@@ -6261,49 +6261,15 @@ are both equivalent to
 @noindent
 but they may be more convenient to write,
 especially in the presence of more arguments.
- at footnote{If there is a single inst or a single mode
-that all instances of a given type are expected to use,
-programmers will often give that inst or mode
-the same name as the name of the type.
-The compiler looks up names in its type table when it expects a type,
-in its inst table when it expects an inst,
-and in its mode table when it expects a mode,
-so this does not confuse the compiler.
-However, this practice @emph{can} confuse Mercury programmers
-who (a) do not know this fact, or (b) are not familiar with this convention.}
-
-As a convenience, the language allows the @samp{in()} wrapper
-around higher order insts, which turn them into higher order modes,
-to be omitted in the mode declarations of predicates and functions.
- at c ZZZ or is that true more generally, of all places that expect modes
- at c but find insts?
- at c I (zs) don't know the answer.
-In those parts of these declarations
-where the compiler expects to find a mode, if it finds an inst instead,
-it implicitly inserts the @samp{in()} around that inst.
-This is why the usual mode of @samp{list.foldl},
-which we introduced above as being
-
- at example
-:- mode foldl(in(pred(in, in, out) is det), in, in, out) is det.
- at end example
-
- at noindent
-can also be written as
-
- at example
-:- mode foldl(pred(in, in, out) is det, in, in, out) is det.
- at end example
-
- at noindent
-and is actually written in the source code like this.
- at c ZZZ *Should* it be written like that?
- at c Arguably, it makes the code harder to read for novices.
-
- at c ZZZ can you omit the in(...) wrapper around named insts?
- at c Answer: NO. it is not even true of the inst is an inst name that expands
- at c to a higher order inst, rather than being an *explicit* higher order inst.
- at c ZZZ Next question: *why* is the answer NO?
+ at footnote{If all instances of a given type are expected to use
+a single inst or a single mode,
+there is a convention where programmers will give that inst or mode
+the same name as the type.
+This works because types, insts and modes belong to separate namespaces
+so the names do not conflict.
+Nonetheless, there is usually no need to define a named mode.
+It is clearer to write a mode using @samp{in()} or @samp{out()}
+around a named inst.}
 
 The general form of higher order insts follows one of two patterns,
 one for predicates, and one for functions.
@@ -6344,6 +6310,34 @@ around any instances of these patterns in Mercury code.
 @c modes include higher order insts/modes, which would be too complex to
 @c be useful as an example to novices.
 
+As a convenience,
+the language allows you to write a higher order @emph{mode}
+using the same syntax as a higher order @emph{inst}.
+If @var{HOInst} has the form of a higher order inst,
+then writing @var{HOInst} where a mode is required
+is the same as writing @samp{in(HOInst)},
+which is in turn equivalent to @samp{HOInst >> HOInst}.
+Therefore,
+you can omit @samp{in()} around the higher order inst of an input argument.
+For example,
+
+ at example
+:- mode foldl(in(pred(in, in, out) is det), in, in, out) is det.
+ at end example
+
+ at noindent
+can also be written as
+
+ at example
+:- mode foldl(pred(in, in, out) is det, in, in, out) is det.
+ at end example
+ at c ZZZ *Should* it be written like that?
+ at c Arguably, it makes the code harder to read for novices.
+
+As usual,
+if a predicate or function has only one mode,
+the @samp{pred} or @samp{func} declaration
+can be combined with the @samp{mode} declaration.
 Consider the declaration of a function
 that computes the intersection of two maps from keys to values:
 



More information about the reviews mailing list