mthom / scryer-prolog

A modern Prolog implementation written mostly in Rust.
BSD 3-Clause "New" or "Revised" License
2.01k stars 119 forks source link

Defined predicates sometimes yield unexpected existence errors #2454

Open triska opened 2 months ago

triska commented 2 months ago

For instance, when defining f/0 as:


f :- false, _ is [_|_].

I get:

$ scryer-prolog 
?- [user].
f :- false, _ is [_|_].

   error(type_error(evaluable,'.'/2),load/1).
?- f.
   error(existence_error(procedure,f/0),f/0), unexpected.
   false. % expected

I found this issue based on a recent question on StackOverflow: https://stackoverflow.com/q/78774323

haijinSk commented 2 months ago

I apologize, but to be honest, I have a problem to understand the wording "defined" in the title. If there is an error at the end of defining a predicate, then, from my naive perspective, the existence error is expected, because the predicate is not defined (it was not accepted by the Prolog system).

Or, I suspect, I see it from the wrong point of view, perhaps I completely misunderstood this issue.

triska commented 2 months ago

In the above example, f/0 is user-defined in the terminology of the Prolog standard:

3.195 user-defined procedure: A procedure which is
defined by a sequence of clauses where the head of each
clause has the same predicate indicator, and each clause
is expressed by Prolog text or has been asserted during
execution (see 8.9).
haijinSk commented 2 months ago

Thank you for the explanation of the term "defined".

I'm an extremely naive user, I simply see: the "defined" predicate is not accepted by the Prolog system in the first place (the system says "type_error", however unexpected here). Therefore I see the "existence_error" as expected. In my perspective, in my "languaging", the unexpected is not accepting the predicate.

hurufu commented 2 months ago

Updated comment: This is 100% reproducible error starts somewhere around compile_is function. Will try to investigate further.

hurufu commented 2 months ago

Whole loading of a new terms has a few steps. In one of the first steps it tries to expand whatever is possible to expand, and then it tries to compile. There is a special set of functions for handling arithmetic expressions, mainly there is this code that explicitly produces an error when a list (or string) is found. So I think that changing compiler behavior is a bad idea in such case, so I decided to expand away invalid arithmetic expression to throw(error(not_evaluable)). UPD: It is done a little bit differently now.

I have no idea if this is a good place of doing this, but I think general picture is clear.

P.S. It is possible to learn a bit of Rust in one weekend ;)

triska commented 2 months ago

Other arithmetic operations are also affected by this issue. For instance:

f :- false, _ > [_|_].
triska commented 2 months ago

It's also not limited to [_|_] as the outermost expression. The following also yields an error:

f :- false, _ is 5+[_|_].
UWN commented 1 month ago

Just a general remark. Fixing this issue currently does not make much sense, because the deeper problem behind is the current representation of partial strings. So fixing this will only delay the transition towards a better representation.

hurufu commented 1 month ago

Thanks, understood, but it also fails for other kinds of invalid arithmetical expressions, is it also expected?

?- [user].
f :- false, _ is foo.

   error(type_error(evaluable,foo/0),load/1).
?- f.
   error(existence_error(procedure,f/0),f/0).
triska commented 1 month ago

Just a general remark. Fixing this issue currently does not make much sense, because the deeper problem behind is the current representation of partial strings. So fixing this will only delay the transition towards a better representation.

I think this comment rather applies to #2455 instead of the present issue?