I am trying to make a predicate in order to validate if a given input represents a formula.
I am allowed to use only to propositional atoms like p, q, r, s, t, etc. The formulas which I have to test are the following:
neg(X) - represents the negation of X
and(X, Y) - represents X and Y
or(X, Y) - represents X or Y
imp(X, Y) - represents X implies Y
I have made the predicate wff
which returns true if a given structure is a formula and false the otherwise. Also, I don't have to use variables inside the formula, only propositional atoms as mentioned bellow.
logical_atom( A ) :-
atom( A ),
atom_codes( A, [AH|_] ),
AH >= 97,
AH =< 122.
wff(A):-
\+ ground(A),
!,
fail.
wff(and(A, B)):-
wff(A),
wff(B).
wff(neg(A)):-
wff(A).
wff(or(A, B)):-
wff(A),
wff(B).
wff(imp(A, B)):-
wff(A),
wff(B).
wff(A):-
ground(A),
logical_atom(A),
!.
When i introduce a test like this one,
wff(and(q, imp(or(p, q), neg(p)))).
, the call returns both the true
and false
values. Can you please tell me why it happens like this?
Since Prolog is based heavily on formal logic, it's useful to have some experience with it before starting to learn the language. This is a short introduction to logic for people who want to learn Prolog. It will discuss two logical languages: propositional logic and first-order logic.
A Prolog program consists of a set of premises, the database. A user interacts with the database by submitting queries (goals to be proved). The Prolog interpreter uses predicate logic to prove or to refute the queries. The simplest form of premise is a primitive proposition, like these two: expensive(car).
Prolog has its roots in first-order logic, a formal logic, and unlike many other programming languages, Prolog is intended primarily as a declarative programming language: the program logic is expressed in terms of relations, represented as facts and rules.
In Prolog, predicate names and bound variables are expressed as a sequence of alphanumeric characters beginning with an alphabetic. Variables are represented as a string of alphanumeric characters beginning (the first character, at least) with an uppercase alphabetic. Thus: likes(X, susie).
The data structure you chose to represent formulae is called "defaulty", because you need a "default" case to test for atomic identifiers: Everything that is not something of the above (and, or, neg, imp) and satisfies logical_atom/1 is a logical atom (in your representation). The interpreter cannot distinguish these cases by their functor to apply first-argument indexing. It is much cleaner to, in analogy to and/or/etc., also equip atomic variables with their dedicated functor, say "atom(...)". wff/1 could then read:
wff(atom(_)).
wff(and(A, B)) :- wff(A), wff(B).
wff(neg(A)) :- wff(A).
wff(or(A, B)) :- wff(A), wff(B).
wff(imp(A, B)) :- wff(A), wff(B).
Your query is now deterministic as desired:
?- wff(and(atom(q), imp(or(atom(p), atom(q)), neg(atom(p))))).
true.
If your formulae are initially not represented in this way, it is still better to first convert them to such a form, and then to use such a representation which is not defaulty for further processing.
An additional advantage is that you can now easily not only test but also enumerate well-formed formulae with code like:
wff(atom(_)) --> [].
wff(and(A,B)) --> [_,_], wff(A), wff(B).
wff(neg(A)) --> [_], wff(A).
wff(or(A,B)) --> [_,_], wff(A), wff(B).
wff(imp(A,B)) --> [_,_], wff(A), wff(B).
And a query like:
?- length(Ls, _), phrase(wff(W), Ls), writeln(W), false.
Yielding:
atom(_G490)
neg(atom(_G495))
and(atom(_G499),atom(_G501))
neg(neg(atom(_G500)))
or(atom(_G499),atom(_G501))
imp(atom(_G499),atom(_G501))
and(atom(_G502),neg(atom(_G506)))
and(neg(atom(_G504)),atom(_G506))
neg(and(atom(_G504),atom(_G506)))
neg(neg(neg(atom(_G505))))
neg(or(atom(_G504),atom(_G506)))
neg(imp(atom(_G504),atom(_G506)))
etc.
as its output.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With