[m-users.] Free and Ground in the same error line?

Sean Charles (emacstheviking) objitsu at gmail.com
Wed Nov 1 02:38:13 AEDT 2023



> On 31 Oct 2023, at 12:41, Zoltan Somogyi <zoltan.somogyi at runbox.com> wrote:
> 
> 
> On 2023-10-31 23:13 +11:00 AEDT, "Julien Fischer" <jfischer at opturion.com <mailto:jfischer at opturion.com>> wrote:
>> 
>> On Sat, 28 Oct 2023, Sean Charles (emacstheviking) wrote:
>> 
>>> I rewrote it like this, could it be any leaner? Asking in case I am not as good as I can be yet :D !
>>>     384 get_class_superclass(Class, Super, !X) :-
>>>     385     ( if !.X = [ tk(Cp, Cb) | Rest ] then
>>>     386         Class = ps(Cp, Cb),
>>>     387         Super = no,
>>>     388         !:X   = Rest
>>>     389     else if !.X = [ sexp(_, [ tk(Cp, Cb), tk(Sp, Sb) ]) | Rest ] then
>>>     390         Class = ps(Cp, Cb),
>>>     391         Super = yes(ps(Sp, Sb)),
>>>     392         !:X   = Rest
>>>     393     else
>>>     394         fail
>>>     395     ).
> 
> Note that you *can* write the condition of that first if-then-else as
> 
>  if !.X = [tk(Cp, Cb | !:X] then ...
Intersting!

> 
> I expect that you wrote Rest in place of !:X there because you cannot bind
> variables visible from outside the if-then-else in the condition.

Yes, exactly that, the compiler has conditioned me.

> State variable syntax is not an exception to that, but it looks like an exception.
> The reason is that the compiler, of course, knows this rule. Therefore if
> the condition updates a state variable, then the compiler will itself
> add the unification that corresponds to !:X = Rest in your code.

I will do this and see for myself.
> 
> In concrete terms, if the version of !X just before the if-then-else is
> version 0 (the initial version, as in this case), and the condition updates it
> to the next version, version 1, then the compiler knows that version 1 cannot
> be made visible outside the if-then-else. So if the then-part does not itself
> update !X to a version later than 1, then the compiler will do so itself,
> by adding a unification between versions 1 and N in the then-part,
> and will make version N the version visible in the code after the if-then-else.
> N will be the maximum of 2 and whatever the current version at the end of
> the else part is.
> 
> It is therefore possible, and meaningful, to write code such as
> 
> ( if !.X = ["abc" | :!X] then
>   true
> else
>    true
>  )
> 
> If !.X is a list of strings, then this will remove an initial "abc"
> from that list, if the list starts with that string. The then-part
> does not have to do anything. The work is done by the condition,
> and the then-part just passes its result to the code after the if-then-else.
> 
>>>> I mean, it's fine but in the manual, 2.13 DCG-rules it says "As a
>>> matter of style, we recommend that in future DCG notation be reserved
>>> for writing parsers and sequence generators, and that state variable
>>> syntax be used for passing state threads."
>> 
>> I would not read too much into that recommendation.  It was written as
>> part of the change that added state variables to the Mercury language.
>> At that point, no one had much experience using, for parsers or sequence
>> generators, or anthing else.  My opinion, with the benefit of twenty
>> years of hindsight, is don't use DCGs.  (The one exception to that
>> might be if I were in the process of porting an existing Prolog
>> program to Mercury.)
> 
> I agree with that. I would also add, in response to an earlier email
> in this thread, that while you *can* use both DCGs and state variables
> in a single clause, you definitely *shouldn't*. That is just asking for
> trouble, in that any future maintainer of that code will curse your name :-(
> And that will be true even if that maintainer is an future. version of you.
> 
> Zoltan.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurylang.org/archives/users/attachments/20231031/5955d4d0/attachment-0001.html>


More information about the users mailing list