[m-dev.] pragmas should specify pred/func as well as name and arity
Peter Wang
novalazy at gmail.com
Thu Apr 29 14:33:34 AEST 2021
On Thu, 29 Apr 2021 12:38:21 +1000 "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:
> Most pragmas tell the compiler something about a predicate
> or function. We have two pieces of syntax that pragmas use to specify
> *which* predicate or function. The first syntax we implemented was simple name/arity.
> The other, implemented later, is either pred(argmode1, ..., argmodeN),
> or func(argmode1, ..., argmodeN) = retmode.
> The latter of course was intended to be more precise, because it was
> intended to specify one *procedure* of a predicate or function. But it is
> also more precise in another way: it actually specifies whether it applies
> to a predicate or function, which the first syntax does not.
>
> This leaves open the door to a potential problem where the programmer
> intends a pragma to apply to e.g. pred foo/2, but the compiler also
> applies it to func foo/2.
>
> This has not been a significant problem in the past, for two reasons.
> First, the first pragmas we implemented (apart from things like foreign_procs,
> which look like pragmas syntactically but which we now handle as the
> totally separate kind of thing they are) were things like pragma inline,
> for which it did not matter all that much whether it applied to both
> a pred and a func, or to just the one the programmer meant.
> The second reason, unique to us, is that we tended to frown on
> having both a pred foo/2 *and* a foo/1, so the issue was rarely relevant,
> though we *do* have some instances of defining e.g. both pred foo/2
> and pred foo/3, and then *function versions of both*, i.e. func foo/1
> and func foo/2.
>
> However, for pragmas that assert something, such as promise_pure,
> applying them to both a predicate and a function when the programmer
> intended applying them to only one is a more significant problem.
> I believe we should update the pragmas that use the first syntax
> to first allow, and eventually require, the programmer to say whether
> they mean pred foo/2 or func foo/2.
Can we require something more specific than name/arity if there is
actual ambiguity? I already dislike having to specify the arity when
there is only one such thing by that name.
> I can see three broad approaches to how this could be done.
>
> Approach 1 would be to wrap the name/arity pair in either pred() or func().
> This would look good, but unfortunately the second syntax also uses terms
> whose top function symbol is either pred or func, and there are some pragmas
> that allow the subject that they apply to to be specified using either the first
> or the second syntax (see attached table), so this would probably serve
> as a source of confusion. And the compiler's error messages, having to
> describe two possible ways to fix any syntax errors (one to reach each kind
> of valid syntax), couldn't help as much as we would like them to.
This seems ideal to me. I don't really understand the problem with error
messages. If the compiler cannot parse the term, I think the compiler
can just say something like:
The argument must have one of these forms:
NAME/ARITY
pred(NAME/ARITY)
func(NAME/ARITY)
NAME(MODES)
and the user should get the idea.
>
> Approach 2 would be to add a "_pred" or "_func" suffix to the pragma name,
> such as ":- pragma inline_func(foo/2).". We have already used this approach
> when replacing ":- external(foo/2)." with ":- external_{pred,func}(foo/2).".
> However, there are some pragmas, such as "terminates", for which neither
> that suffix, nor a similar prefix, would look all that natural.
I don't especially like it.
> Approach 3 would be to add an extra argument, containing simply either
> "pred" or "func", to the pragma's argument list, just before the argument
> that now contains just foo/2.
If the argument was optional then I could ignore it :)
>
> There is also what we might call "approach 0": simply obsolete the pragmas,
> such as promise_pure, whose effect can be accomplished by wrappers
> around goals.
pragma promise_pure is not redundant because this is correct:
:- pred foo(io::di, io::uo) is det.
:- pragma promise_pure(foo/2).
foo(!IO) :-
impure do_foo.
but this is wrong:
foo(!IO) :-
promise_pure (
impure do_foo
).
I supposed you could ensure that !IO appears inside the impure goal.
Peter
More information about the developers
mailing list