1
votes

I working in prolog for first time. I am trying to convert operations in text. Such as, THREE + THREE = SIX should return true. I tried this. I am getting error on last line and when I try add(ONE,ONE,TWO) it returns false instead of true.

numericValue(ONE, 1).
numericValue(TWO, 2).
numericValue(THREE, 3).
numericValue(FOUR, 4).
numericValue(FIVE, 5).
numericValue(SIX, 6).
numericValue(SEVEN, 7).
numericValue(EIGHT, 8).
numericValue(ZERO, 0).
numericValue(NINE, 9).


add(num1,num2,num3):-
    numericValue(num1,a),
    numericValue(num2,b),
    numericValue(num3,c),
    (c =:= a+b -> true ; false).

istBiggerThen(XinEng,YinEng) :-
    numericValue(XinEng, X),
    numericValue(YinEng, Y),
    (  X < Y -> true ;  false).

A  + B = C :- add(A,B,C).

Error on last line is

ERROR: /home/name/prolog_examples/crypt.pl:24:
No permission to modify static procedure `(=)/2'
1
One major issue you have is that, in Prolog, variables start with a capital letter, and atoms (constants) start lower case. You seem to have this reversed in several places. Also, =/2 is the built-in unification operator (it's not arithmetic equality of expressions). When you enter A + B = C :- add(A,B,C) it's an attempt to redefine what =/2 means, which isn't allowed.lurker

1 Answers

2
votes

literals (lower-case) vs. Variabls (upper-case):

as @lurker pointed out, you have your atoms and variables mixed up. So your facts should look something like this:

text_to_number(one, 1).
text_to_number(two, 2).
text_to_number(three, 3).
%% etc...

while your rules will need to use variables, like so:

add(A_Text, B_Text, C_Text) :-
    text_to_number(A_Text, A_Num),
    text_to_number(B_Text, B_Num),
    C_Num is A_Num + B_Num,
    text_to_number(C_Text, C_Num).

bigger_than(A_Text, B_Text) :-
    text_to_number(A_Text, A_Num),
    text_to_number(B_Text, B_Num),
    A_Num > B_Num.

The reason reason why add(ONE, ONE, TWO) turns out false is because your original rule for add/3 only defines relationships between the atoms num1, num2, num3, a, b, c. When you query add(ONE, ONE, TWO) Prolog tries to unify the variables with the atoms in the head of your rule, which is add(num1, num2, num3). Because you have ONE as the first and second argument of your query, this unification is impossible, since ONE = ONE but num1 \= num2. As there are no further rules or facts for add/3, the query simply returns false.


Using the pattern (|Condition| -> true ; false):

Statements in the body of a clause (i.e., to the right of the :- operator) is evaluated to be either true or false, so you will almost never need to use the pattern (|Condition| -> true ; false). E.g. C_Num is A_Num + B_Num is true iff C_Num can be unified with the sum of A_Num and B_Num, or else it is false, in which case Prolog will start back tracking.


Using =:=/2 vs. is/2:

=:=/2 checks for the equality of its first argument with the value of its second argument, which can be an arithmetical expression that can be evaluated using is/2. Query ?- X =:= 2 + 2 and you'll get an instantiation error, because =:=/2 cannot compare a free variable to a mathematical expression. is/2, on the other hand, unifies the variable on the left with the value of the expression on the right: ?- X is 2 + 2. X = 4.

Your use of =:=/2 would work (provided you straightened out the variable-atom thing), but your rule describes an inefficient and roundabout solution for the following reason: since numericValue(Num3,C) precedes evaluation of the arithmetic, Prolog will first unify numericValue(Num3,C) with the first fitting fact, viz. numericValue(one, 1) then test if 1 =:= A + B. When this fails, Prolog will unify with the next fact numericValue(two, 2) then test if 2 =:= A + B, then the next... until it finally happens upon the right value. Compare with my suggested rule: the numeric values A_Num and B_Num are summed with C_Num is A_Num + B_Num, unifying C_Num with the sum. Then Prolog unifies text_to_number(C_Text, C_Num) with the single fitting fact that has the appropriate value for C_Num.


Defining operators:

When a term appears on the right of a :-, or on the top level of the program, is being defined. However, you cannot simply redefine predicates (it can be done, but requires some bookkeeping and special declarations. Cf., dynamic/1). Moreover, you wouldn't want to redefine core terms like +/2 and =/2. But you can define your own predicates with relative ease. In fact, going crazy with predicate definitions is one of my favorite idle things to do with Prolog (though I've read cautions against using unnecessary operators in practice, since it makes your code recondite).

Operators are declared using op/3 in a directive. It has the signature op(+Precedence, +Type, :Name) (Cf., the SWI-Prolog documentation):

:- op(200, xfx, user:(++)).
:- op(300, yfx, user:(=::=)).

A ++ B =::= C :- add(A, B, C).

In action:

?- one ++ two  =::= X.
X = three.