[m-users.] Inst error on !IO mode in DCG rule

Sean Charles (emacstheviking) objitsu at gmail.com
Mon May 17 17:51:06 AEST 2021


Premature send from mail.app, apologies list!

> Excellent explanation as usual Zoltan. I get it now, and the printer paper analogy really really made the light come on about that.
> As it turned it, the logic didn’t feel right
…didn’t feel right and so I changed the parse to be deterministic and then implemented execute:


:- pred execute(string::in, io::di, io::uo) is det.
execute(Input, !IO) :-
    lexer.on_string(chomp(Input), Lx, !IO),
    % dump_lexer(Lx, !IO),
    ( if lex_error(Lx) = yes(ok_eob) then
        parse_cmd(CmdRes, tokens(Lx), _),
        (
            CmdRes = no,
            (if list.length(tokens(Lx)) > 0
            then io.format("Try ?, h or help.\n", [], !IO)
            else true)
        ;
            CmdRes = yes(help),
            show_help_for("help", !IO)
        ;
            CmdRes = yes(help_for(Topic)),
            show_help_for(Topic, !IO)
        )
    else
        io.format("%sERROR! %s\n",
            [s(prompt), s(string(lex_error(Lx)))], !IO)
    ).

It’s all working fine and the parsing of commands is now as clean as I hoped it should be now that my tokeniser works.

:- type ltok == list(token).
:- type cmd ---> help; help_for(string).

:- pred parse_cmd(maybe(cmd)::out, ltok::in, ltok::out) is det.
parse_cmd(Cmd) -->
    ( if help_cmd, [tk(_, Subject)] then
        {Cmd=yes(help_for(Subject))}
    else if help_cmd then
        {Cmd = yes(help)}
    else
        {Cmd=no}
    ).

:- pred help_cmd(ltok::in, ltok::out) is semidet.
help_cmd --> [tk(_, "help")] ; [tk(_, "?")] ; [tk(_, "h")].

Thanks again for your help it is always very welcome and much appreciated.
Sean.




> On 17 May 2021, at 08:47, Sean Charles (emacstheviking) <objitsu at gmail.com> wrote:
> 
> Excellent explanation as usual Zoltan. I get it now, and the printer paper analogy really really made the light come on about that.
> As it turned it, the logic didn’t feel right
> 
>> On 17 May 2021, at 02:45, Zoltan Somogyi <zoltan.somogyi at runbox.com> wrote:
>> 
>> 
>> 2021-05-17 06:36 GMT+10:00 "Sean Charles (emacstheviking)" <objitsu at gmail.com>:
>>>   execute(Input, !IO) :-
>>>       lexer.on_string(chomp(Input), Lx, !IO),
>>>       % dump_lexer(Lx, !IO),
>>>       ( if lex_error(Lx) = yes(ok_eob) then
>>>             io.format("DCG this: %s\n", [s(string(tokens(Lx)))], !IO),
>>> 96 ===>       ( if parse_cmd(!IO, tokens(Lx), _) % do I care what's left?
>>>             then io.format("DID IT\n", [], !IO)
>>>             else io.format("PARSE FAILED\n", [], !IO)
>>>             )
>>>       else
>>>           io.format("%sERROR! %s\n”,
>>>               [s(prompt), s(string(lex_error(Lx)))], !IO)
>>>       ).
>> 
>> The condition of that if-then-else does two things.
>> 
>> 1: It calls parse_cmd, which destroys the old state of the world (call it IO_0)
>>   and creates a new state of the world (call it IO_1).  This code is det,
>>   i.e. it cannot fail.
>> 
>> 2: It checks whether the third arg returned by parse_cmd is unifiable
>>   with tokens(Lx). This code is semidet, i.e. it can fail.
>> 
>> You are getting the error because the compiler knows that  if the
>> unification with tokens(Lx) fails, then the condition as a whole fails,
>> and execution would have to go on to the else case, *with the current
>> state of the world being IO_0*. (This is because the semantics of
>> an if-then-else is "either execute the conjunction of the condition
>> and then then-part, or execute the else-part, depending on whether
>> the condition succeeds.) But the compiler also knows that the
>> call to parse_cmd destroyed IO_0, and there is no way to get it back.
>> It's like you tell a printer to print something, then later tell it
>> never mind, give me back the blank paper you started with.
>> In other words, you cannot do I/O in places that can be
>> backtracked over.
>> 
>> The fix is simple. Move the call to parse_cmd to *before* the if-then-else,
>> and leave only the test of whether the third arg it returns is tokens(Lx)
>> in the condition.
>> 
>> Zoltan.
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurylang.org/archives/users/attachments/20210517/5bd0ba31/attachment.html>


More information about the users mailing list