[m-users.] Inst error on !IO mode in DCG rule
Zoltan Somogyi
zoltan.somogyi at runbox.com
Mon May 17 11:45:57 AEST 2021
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.
More information about the users
mailing list