2
| ?- [user].
compiling user for byte code...
formula_0(P, Q):- (P; Q), \+ P.

user compiled, 2 lines read - 768 bytes written, 37208 ms

yes
| ?- formula_0(P, Q).
uncaught exception: error(instantiation_error,formula_0/2)

All I basically want to do is to ask is the set of expressions {P or Q, ~P} satisfiable?

But the error message is not helping here...

PS. The answer should be "yes", this formula is satisfied when P = false and Q = true.

repeat
  • 18,496
  • 4
  • 54
  • 166

3 Answers3

3

The reason you get an instantiation error is that too little is known about P and Q to say anything about them at the time they are used as goals. You are right that when you ask for example:

?- G.

then G = true is a solution that makes the query succeed. But so is for example G = (a=a) because a=a is also true. Since it is not possible to enumerate all goals G that succeed, you get an instantiation error. But notice for example that when you explicitly give a binding, you get the result you expect:

?- G = true, G.
G = true.

So, you should provide a set of values you are interested in:

?- maplist(boolean, [P,Q]), formula(P, Q).

and define for example:

boolean(true).
boolean(false).

to obtain concrete solutions. Or use constraints, which let you constrain the domain of variables before using them.

EDIT: Since there was some discussion about this, I go into more detail. The main question that arose is: Why does the query

?- Q.

not succeed with the sole solution

Q = true.

since obviously, true succeeds and is thus a valid solution? Answer: There are other possible answers as well, since true is not the only goal that succeeds. For example, the conjunction (true,true) succeeds as well. Suppose now that Q = true were the only solution to the above query, then it would be the case that:

?- Q, Q = (true, true).

fails (since dif(true, (true,true)) is itself true), but simply exchanging the goals like

?- Q = (true,true), Q.

succeeds because otherwise ?- true, true would also have to fail and that cannot be the case. This would violate commutativity of conjunction already for the most basic predicate (unification).

Note that while true and (true,true) both succeed when executed as goals, they are obviously different terms and cannot replace each other in general. Similarly, the term append([], [], []) is different from the term true, although both succeed when executed as goals. You therefore get an instantiation error, since too little is known about Q in a query like ?- Q. to give useful results.

mat
  • 40,498
  • 3
  • 51
  • 78
  • Coming from Common Lisp background, this sounds a bit strange... is there anything else in Prolog which is also "false", but it is not "fail"? Or, worded differently, is there a type system that tells you what happens to a value, if it is in boolean context? I just imagined that anything in boolean context would be "true", except for "fail", so that if the solver couldn't think of a unique "true" value, it would just try with the unique "false" value (of which there's just one anyway). Sorry if this makes little sense. –  Oct 09 '13 at 09:27
  • Oh, and by the way, thanks for explanation. At least now I know how to get it to work! –  Oct 09 '13 at 09:33
  • 1
    Lots of things are declaratively equivalent to `false`, for example `0=1`, so you can also write for example `a=b` instead of `false` everywhere you use it. As I said, consider using *constraints* if you know beforehand which values you are reasoning about, check out GNU Prolog's built-in finite domain constraint solver for example, or `library(clpfd)` in YAP, SWI and SICStus Prolog, with which you can write `Value in 0..1`, and the solver automatically deduces `Value = 1` when you say `Value #\= 0`. – mat Oct 09 '13 at 10:27
  • This still, well, at least for me, is begging a question... if all those multiple false values exist (I wouldn't even call them values), but they reduce to false anyway, why even be bothered with their existence? But I'll leave this question for later, that's just too much info to process at one time. Thanks for suggesting the library. –  Oct 09 '13 at 11:01
  • 1
    Every Prolog goal, and Prolog goals are naturally represented in Prolog as Prolog *terms*, either fails or succeeds (or throws an exception). You can call your `formula_0/2` also for example as: `formula_0(0=1, append([],[],[]))` and see that it succeeds because the given goals (represented as terms) have fitting truth values. However, since you explicitly tagged your question with `boolean`, you likely are interested only in Boolean values, which you can for example represent with the Prolog atoms `true` and `false` or, arbitrarily, with `+`/`-` or `t`/`f`, which cannot be called directly. – mat Oct 09 '13 at 11:21
  • Well, I'd not call those values. To me they look like unreduced expressions, and given there is some semantic for what *values* must fit into a `formula(X, Y)` it shouldn't even care about how to reduce those things you wrote, because they can *only* be reduced to either `false` or `true`. I.e. I understand now what you did by creating `boolean` constraint, but I don't understand why this is not a default behaviour. I can't see anything bad happening if it was a default... –  Oct 09 '13 at 12:22
  • In other words, I'd expect the default behaviour to be, in human language: "if a thing is not defined, then it must be either true or false, because nothing else is possible, or we cannot care less about other outcomes". –  Oct 09 '13 at 12:24
  • As I said, it can be other things as well in addition to just the goals `true` or `false`, because Prolog is an approximation of first order logic, allowing and providing predicates and not only Boolean values. For example, the goal `X = [_|_]` (i.e., the predicate `=/2`) also succeeds and additionally constrains a variable. `true` is the most general goal, it always succeeds. `false` is the most specific constraint, it always fails. It makes sense to have these as built-ins, but it does not mean that they are the only possible declarative solutions to the query `?- G.` or `?- \+ G`. – mat Oct 09 '13 at 13:01
  • Sorry, I'm not convinced, I just read this as a repetition of the above. But I really don't want to argue. I don't know the motivation behind this decision. –  Oct 09 '13 at 14:39
  • I've edited the post and added more explanation. I hope it helps. – mat Oct 09 '13 at 18:53
  • Sorry, it's just me being stubborn. :) But it doesn't really explain why does it happen. It only explains that this is how it works. Which is okay, because I can't fix it anyway, but there's really no reason for things to be this way. It's just an arbitrary choice of the language developers. If you will try to take my perspective for a second: semantic of the language require that any valid grammar product, which is also semantically valid, be reducible to `{true, false, error, never-halt}`. These are the *only* options. `(true, true)` reduces to `true` etc. –  Oct 09 '13 at 20:38
  • So, if you have a basic predicate (just a no-predicate case), then you have to observe that: 1) It is not the case that there is an error (no code = no error). 2) The program definitely halts. 3) So it is either true or false. Now, if there were, for example, other values, not reducible to booleans, like, numbers, or strings, or lists - you name it, then it would be too much to ask to consider *all* options. But since there are only two - it's not that much to ask to try them both. And if I didn't specify any predicate to refine my question - then why not trust me? Just assume there isn't one. –  Oct 09 '13 at 20:41
  • `true` and `false` are the only possibilities in *Boolean* logic, but not in predicate logic, where you have predicates over terms. Consider the query `?- X = a`. The predicate succeeds, but the result is *not* simply `true`: The result is a binding, a resolution refutation, that tells you *when* the goal is true, namely if `X = a`. You cannot replace this by `true`, which succeeds unconditionally. Similar for constraints like `dif(X, Y)`. Again, the result is *not* just "true", but a specification *when* it is true. So yes, unsurprisingly, first order logic is not reducible to Boolean logic. – mat Oct 09 '13 at 22:52
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/38934/discussion-between-mat-and-wvxvw) – mat Oct 09 '13 at 23:05
3

Use for constraint logic programming over Booleans.

:- use_module(library(clpb)).

Sample query:

?- sat((P+Q) * ~P).
P = 0, Q = 1.                   % succeeds deterministically
repeat
  • 18,496
  • 4
  • 54
  • 166
1

Gnu Prolog supports the 'naked variable' call, a syntactic feature that allows to write code like you show in formula_0/2. But when it come to executing it, variables must be bound !

| ?- P.            
uncaught exception: error(instantiation_error,top_level/0)

| ?- P=write(1), P.
1
P = write(1)

then just use callables:

| ?- formula_0(fail,true). 
yes
CapelliC
  • 59,646
  • 5
  • 47
  • 90