Scryer-prolog: Unexpected silent failure #2

Created on 25 Apr 2020  路  12Comments  路  Source: mthom/scryer-prolog

Currently, I am porting Alzint to Scryer Prolog, a version that runs in Scryer is now available from:

https://www.metalevel.at/alzint/alzint.pl

However, I have run into the following problem:

When ex3.txt contains the following AL(Z) program:

I(x) = 10
I(f) = 1

while (x >= 2) do
  begin
   f <- f * x
  ;
   x <- x - 1
  end

Then the following query unexpectedly fails silently:

?- run('ex3.txt').
...
false.

However, when I use the contents of ex3.txt directly, and use alzint:run_/2 directly, i.e., when I post:

?- alzint:run_("\
I(x) = 10                  \n\
I(f) = 1                   \n\
                           \n\
while (x >= 2) do          \n\
  begin                    \n\
   f <- f * x              \n\
  ;                        \n\
   x <- x - 1              \n\
  end                      \n\
",
   step).

I get, as expected:


 ==>  while (x >= 2) do 
        begin
         f <- f * x
        ;
         x <- x - 1
        end

     f = 1   x = 10   
----------------------------------------------------------------------
(c)ontinue (u)ndo (r)un (q)uit: 
etc.

So, there is obviously a discrepancy between the results, depending on whether I read the contents from a file (using phrase_from_file/2 as provided in #396 by @notoria) or specify them on the toplevel.

387 may be related.

All 12 comments

The Rust string is "I(x) = 10\nI(f) = 1\n\nwhile (x >= 2) do\n begin\n f <- f * x\n ;\n x <- x - 1\n end\n".
But this doesn't work:

?- alzint:run_("I(x) = 10\nI(f) = 1\n\nwhile (x >= 2) do\n  begin\n   f <- f * x\n  ;\n   x <- x - 1\n  end\n").
caught: error(evaluation_error((alzint:run_)/1),run_/1)

What is the inline string?

run_/2 takes two arguments, you can specify step or run as the second one.

For example, the following works:

?- alzint:run_("I(x) = 10\nI(f) = 1\n\nwhile (x >= 2) do\n  begin\n   f <- f * x\n  ;\n   x <- x - 1\n  end\n", step).

In the examples I posted, the lexer and parser work exactly as expected, and the program is apparently correctly parsed, resulting in the same abstract syntax tree in both cases:

stm(3,while(bin(geq,v(x),n(2)),stm(4,sequence(stm(5,assign(f,bin(*,v(f),v(x)))),stm(7,assign(x,bin(-,v(x),n(1))))))))

You can modify run_/2 to emit the AST etc. if needed.

@notoria: What is the best way to detect where the two cases diverge on the Rust level? Can the new debugging infrastructure be used for this?

What is the best way to detect where the two cases diverge on the Rust level?

I can't say much, it depends on the developer.

Can the new debugging infrastructure be used for this?

It could be used but it isn't enough, an idea of where the bug might be is required, the engine has different parts. Everything could be displayed but the output might be huge.

I don't think FileToChars is emitting new line characters to strings. Compare the output of upto_nl//3on the file-read string versus the typed one Markus gave.

From what I can tell, the newlines seem to be present: I can verify this for example by adding a portray_clause/1 goal in run_/2:

run_(Chars, Option) :-
        portray_clause(Chars),
        (   lex_analysis(Chars, Tokens) ->

With this change, I get:

?- run('ex3.txt').
"I(x) = 10\nI(f) = 1\n\nwhile (x >= 2) do\n  begin\n   f <- f * x\n  ;\n   x <- x - 1\n  end\n".

false.

However, when I manually specify the exact same string that was emitted here on the toplevel (instead of reading it from a file), it works exactly as expected:

?- alzint:run_("I(x) = 10\nI(f) = 1\n\nwhile (x >= 2) do\n  begin\n   f <- f * x\n  ;\n   x <- x - 1\n  end\n", step).
"I(x) = 10\nI(f) = 1\n\nwhile (x >= 2) do\n  begin\n   f <- f * x\n  ;\n   x <- x - 1\n  end\n".

 ==>  while (x >= 2) do
        begin
         f <- f * x
        ;
etc.

Also, thank you a lot for looking into this issue! This issue and #421 are currently blocking my porting work on library(simplex), because I have a test case where the library fails, and it is not clear whether there is a mistake in the library or somewhere else.

That's strange. I looked at the Lines variable of run_ in both cases, after phrase(lines(Chars), Lines) is called. In the inline case, Lines is divided into strings, split at each occurrence of \n, but when run is called on ex3.txt, it isn't.

Yes, I also see such strange effects!

When I define cs/1 in alzint.pl just so that the file is read into a list of characters:

cs(Chars) :- phrase_from_file(list(Chars), 'ex3.txt').

Then indeed the splitting on '\n' does not work, even though '\n' appears to be present in the string, judging from the answer:

?- alzint:cs(Cs),
   alzint:upto_nl(Cs, As, Bs).
   Cs = "I(x) = 10\nI(f) = 1\n ...", As = "I(x) = 10\nI(f) = 1\n ...", Bs = []
;  false.

For comparison, when I take the answer, it works correctly:

?- alzint:upto_nl("I(x) = 10\nI(f) = 1\n ...", As, Bs).
   As = "I(x) = 10", Bs = "I(f) = 1\n ...".

It works beautifully now, thank you a lot!

If possible, could you please have a look at #421 too? Thank you!

Also, one follow-up question:

Why did it make a difference whether the string was specified on the toplevel or read from a file? They both seem to use the same efficient packed representation.

FileToChars does not use partial strings, it emits a list of characters. This deserves a separate issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

UWN picture UWN  路  3Comments

notoria picture notoria  路  4Comments

triska picture triska  路  3Comments

dcnorris picture dcnorris  路  3Comments

UWN picture UWN  路  4Comments