2

A paper about says the following:

The if-then-else and negation constructs in most variants of Prolog are non-logical and unsound: they can cause the system to compute answers which are inconsistent with the program viewed as a logical theory. Some existing logic programming systems such as NU-Prolog and Gödel provide logical and sound replacements for these Prolog constructs. Unfortunately, these systems enforce safety via runtime groundness checks. This effect can increase the runtime of a program by an arbitrarily large factor; if the goals checked for groundness include large terms, the checks can be prohibitively expensive.

NU-Prolog and Gödel look rather dead and non-free, but I still wonder:

  • What are these logical and sound if-then-else replacements?
  • Do they have analogs in SWI or GNU Prologs?
  • How do they work? How could they work? Adding logical negation to Prolog turns it into general FOL, right? You would basically need a general FOL theorem prover to work with it?
  • Are they different from if_/3? if_/3 has to be extended to be used with new conditions. Would one have to do this in NU-Prolog and Gödel also?
MWB
  • 11,740
  • 6
  • 46
  • 91
  • 2
    "How do they work?" not too well apparently – TA_intern Dec 21 '20 at 03:38
  • @TA_intern Come to think of it, `if_(=(...), ...)` uses `dif/2` which also requires groundness checks, no? It sounds like NU-Prolog and Gödel generalized the same mechanism somehow.... – MWB Dec 21 '20 at 04:47
  • 1
    @MaxB: There are no groundness checks in any implementation of `dif/2`. Think of `dif([], [_|_])` or `dif(A,A)` which both are not ground, yet they already succeed resp. fail. And this, independently of whether constraints are used or not. See [this sketch](https://github.com/mthom/scryer-prolog/issues/135#issuecomment-488348886) for a minimal complete implementation. Or maybe look at [`iso_dif/2`](https://stackoverflow.com/a/20238931/772868) first. – false Dec 21 '20 at 07:24
  • See [Indexing dif/2](https://arxiv.org/abs/1607.01590) which mentions MU-Prolog's if-then-else and also constructive negation. (Which would be the next step after giving up groundness). – false Dec 21 '20 at 07:43
  • I am curious as to why @false did not give these. See bios for following which include such desired predicates. [false](https://stackoverflow.com/users/772868/false) and [repeat](https://stackoverflow.com/users/4609915/repeat) – Guy Coder Dec 21 '20 at 10:47
  • @GuyCoder: "did not give these". What do you mean by these? – false Dec 21 '20 at 11:03
  • @false MaxB is asking questions about predicates that I think of as the pure versions of predicates, e.g. `if_/3`. Then you noted `dif/2` and so I was pointing out where there are more such predicates that I think of as the pur versions of predicates and list of these predicates can be found in your bios. The reason I was curious as to why you did not give these is that the way I see the question and the way you see the question must be different and thus there is something to learn. – Guy Coder Dec 21 '20 at 11:33
  • Interesting NU-Prolog [Paper buried in the 1987-12 issue of "The quarterly bulletin of the Computer Society of the IEEE technical committee on Data Engineering"](https://www.researchgate.net/publication/220282520_The_NU-Prolog_Deductive_Database_System) is considered a "deductive database system" not a "logic programming language" (but it does have function symbols, it seems). – David Tonhofer Dec 21 '20 at 15:01
  • _Adding logical not to Prolog turns it into general FOL, right?_ This "not" is still the usual "negation as failure" -- it just refuses to compute nonsense by making sure it is only called for variables that are ground if they are visible outside of the `\+`(which is excellent). That's still not "strong negation" though, so no FOL. (Sidenote: Currently reading "Vivid Logic" by Gerd Wagner ... Classical Logic and thus FOL based on Classical Logic is a misfit for practically anything outside of mathematics ... and even for mathematics itself. So why target it?) – David Tonhofer Dec 21 '20 at 15:25
  • @DavidTonhofer They say "logical negation", so I don't think they mean "negation-as-failure". – MWB Dec 21 '20 at 15:49
  • @MaxB I am pretty sure they don't support strong negation. For that, you need Answer Set Programming or similar much different systems not based on SLD resolution. What they want to do is make negation-as-failure sound ... – David Tonhofer Dec 21 '20 at 15:57
  • @GuyCoder A hodgepodge of "almost pure" predicates is not a good sign that [this question](https://stackoverflow.com/questions/65425800/) can be answered positively: If only a handful of primitives is enough, why do we need to hand-design so many more, using impure constructs? – MWB Dec 25 '20 at 04:10
  • Did you read the [Nu-Prolog manual](https://edoras.sdsu.edu/doc/Nu-Prolog_Manual.pdf)? – false Dec 30 '20 at 08:44

2 Answers2

2

A break through in if-then-else could be a new annotation. By annotation I understand things like mode declarations, determinancy declarations, etc.. For an if then else, a complete declaration would be nice. Lets assume we could declare a predicate or built-in p/n complete. This would mean it has the property for ground arguments t1,..,tn:

   T |- p(t1,..,tn)

- or -

   T |- ~p(t1,..,tn)

Or in short it would be a decidable predicate if the theory T is recursively enumerable. If we then recall that if-then-else is logically:

    ITE(A,B,C) == (A => B) & (~A => C)

We could then use the complete annotation as follows. Lets assume A = p(t1,..,tn). Because of the annotation the Prolog system would try to prove A. If it doesn't succeed, because of the complete annotation, the Prolog system can infer that ~A would succeed. And therefore it can use the else branch without a proof attempt of ~A.

But interestingly this is already what the ISO core standard if-then-else does, (A->B;C) does also only prove A once. So whats the problem? I guess the problem is that A might be more complex and not necessarily ground. Or even that a predicate p/n might be incomplete, or we even don't know whether it is complete. And in all these cases the ISO core standard nevertheless allows us to use the (A->B;C).

The groundness problem can sometimes be solved by using a runtime groundness checks. This is probably what Mercury refers to:

    when(ground(A), (A->B;C))

SWI-Prolog even applies a trick to make the groundness check cheaper, see also some further discussion on Discourse:

%!  trigger_ground(@Term, :Goal)
%
%   Trigger Goal when Term becomes   ground.  The current implementation
%   uses nonground/2, waiting for an   atribtrary  variable and re-check
%   Term  when  this  variable   is    bound.   Previous   version  used
%   term_variables and suspended  on  a   term  constructed  from  these
%   variables. It is clear  that  either   approach  performs  better on
%   certain types of terms. The term_variables/2  based approach wins on
%   large terms that are almost  ground.   Possibly  we need a nonground
%   that also returns the number of tests   performed  and switch to the
%   term_variables/2 based approach if this becomes large.

trigger_ground(X, Goal) :-
    (   nonground(X, V)
    ->  '$suspend'(V, when, trigger_ground(X, Goal))
    ;   call(Goal)
).
0

I found this review of MU- and NU-Prologs here, if anyone's interested:

enter image description here

MWB
  • 11,740
  • 6
  • 46
  • 91