% To run Gnu prolog, type "gprolog" at the Unix prompt. % To load file file.pl type ['file.pl'] at the prompt. Note single quotes % To add clauses from input, type [user]. End with Cntl-D. Note that this % wipes out any previous clauses with the same predicate. % Note: Some of the output messages here are from a different version of % Prolog % prolog | ?- [user]. | parent(elizabeth,charles). | parent(philip,charles). | parent(elizabeth,anne). | parent(philip,anne). | parent(elizabeth,andrew). | parent(philip,andrew). | parent(diana,william). | parent(charles,william). | parent(diana,harry). | parent(charles,harry). | female(elizabeth). | female(anne). | female(diana). | female(sarah). | male(philip). | male(charles). | male(andrew). | male(william). | ^D | user consulted 728 bytes 9.93411e-10 sec. --- Note: The normal prompt in Prolog is | ?-. This is used for --- entering queries. To change to fact-entering mode, use the command --- [user]. A single fact can be entered in Prolog using the predicate --- assertz. Thus, we could have written --- assertz(parent(elizabeth,charles)). --- We also have these facts in this form (with no prompt --- symbol) in a file called "notes_a". To read the facts in --- we would have entered --- [notes_a]. --- or consult(notes_a). --- To change from add fact mode to query mode, type Cntl-D. --- A simple fact in Prolog, called a literal, has the form --- predicate(arg1, arg2, ... argk) --- Note that the open parentheses must follow --- immediately after the predicate. If there is a space between, --- it is a syntax error. Also notice that all queries and all facts --- end in a period. The interpreter just keeps reading along until --- it finds a period. --- In a form like "married(elizabeth,philip)", married is the --- predicate, and elizabeth and philip are the arguments. | ?- parent(charles, william). yes --- Most input from the terminal, to the prompt "?-", are queries. --- This query may be read "Is Charles a parent of William?" --- Note that all facts and all queries end with a period. The Prolog --- interpreter will just go on accepting input until you type a --- period. | ?- male(william). yes | ?- male(frank_sinatra). no --- If Prolog hasn't been told a fact, it assumes the fact is false. | ?- descendant(william,charles). no --- Prolog does not know by itself that if X is a parent of Y then --- Y is a descendant of X. | ?- parent(charles, X). X = william --- User enters carriage return to accept answer. yes --- X and Y are variables, because they begin with capital letters. --- This query means, "Find some X such that charles is the parent of X." --- Prolog returns the first answer that it finds. Since the user --- accepts it, the execution terminates. | ?- parent(elizabeth, X). X = charles ; --- User types a semi-colon ; to ask for more solutions. X = anne ; X = andrew ; no --- Meaning that Prolog cannot satisfy the user's last request --- to find another solution besides the three it has given already. | ?- parent(X,Y). X = elizabeth Y = charles ; X = philip Y = charles ; X = elizabeth Y = anne --- User stops asking for more answers by typing CR yes | ?- parent(elizabeth, Y), male(Y). Y = charles ; Y = andrew ; no --- If a query has two (or more) goals, separated by commas, then --- Prolog looks for an assignment of variables that satisfies both --- parts. It does this by first finding all the values that satisfy --- the first goal, and checking to make sure that it satisfies the --- second. In this case, the binding X=anne, which satisfies the --- first, is thrown out. --- Rules | ?- [user]. | child(X,Y) :- parent(Y,X). | % X is a child of Y if Y is a parent of X. % | | mother(X,Y) :- parent(X,Y), female(X). | % X is a mother of Y if X is a female parent of Y | | father(X,Y) :- parent(X,Y), male(X). | % X is a father of Y if X is a male parent of Y | | son(X,Y) :- child(X,Y), male(X). | % X is a son of Y is X is a male child of Y | | daughter(X,Y) :- child(X,Y), female(X). | % X is a daughter of Y if X is a female child of Y. | ^D | user consulted 632 bytes 0.0166667 sec. yes --- A rule in Prolog has the form GOAL :- FACT1, FACT2 ... FACTk --- where the goal and all the facts are literals. The meaning of --- this rule is, if all the FACTs are true, then the GOAL is true; --- or, to satisfy the GOAL, satisfy all the FACTs; or, if the GOAL --- is invoked, then invoke each of the FACTS, until you succeed --- in satisfying all the facts. --- A rule like this is called a "clause". The goal is called its --- "head", and the facts are called its "body". --- Comments in Prolog either go from a percent sign % to the end of --- the line, or are delimited by /* and */ | ?- child(anne, philip). yes --- Given the goal "child(anne,philip)", --- Prolog finds the rule, "child(X,Y) :- parent(Y,X)" --- It now generates the goal "parent(philip,anne)" which succeeds, --- so it returns "yes" for the original goal. | ?- child(anne, W). W = elizabeth ; --- User types a semicolon. W = philip --- User types carriage return. yes --- Given the goal "child(anne,W)" --- Prolog finds the rule "child(X,Y) :- parent(Y,X)" --- It now generates the goal "parent(W,anne)", which succeeds --- with W = elizabeth. So the original goal succeeds with W = elizabeth. --- The user typed a semicolon to ask for more solutions, so it --- looked for another solution to "parent(W,anne)". It found the --- solution W = philip, which it reported and which was accepted --- by the user. | ?- father(philip,andrew). yes --- Given the goal G1, "father(philip,andrew)" --- Prolog finds the rule "father(X,Y) :- parent(X,Y), male(X). --- So it generates the two goals: --- G2, "parent(philip,andrew)" --- G3, "male(philip)" --- Both of these succeed, so the original goal G1 succeeds. | ?- father(W,andrew). W = philip --- User types carriage return yes --- Given the goal G1 "father(W, andrew)" --- Prolog finds the rule "father(X,Y) :- parent(X,Y), male(X). --- So it generates the two goals: G2, "parent(W,andrew)" and G3, "male(W)" --- It first works on G2. --- The first answer it finds for G2 is W = elizabet(. --- Prolog accepts this answer, and tries it for G3. --- This gives the goal "male(elizabeth)", which fails. --- So Prolog goes back to G2. --- The second answer it finds for G2 is W = philip --- This version of G3 "male(philip)" succeeds --- So G1 succeeds with W = philip. --- In general, when Prolog fails on some goal, it goes back to the --- last goal it tried, and see if it can find some other solution --- to the last goal that will make things work. This is called --- "chronological backtracking". | ?- daughter(W,elizabeth). W = anne yes --- Given the goal G1: "daughter(W,elizabeth)" --- Prolog finds the rule "daughter(X,Y) :- child(X,Y), female(X)." --- So it generates the two goals: G2, "child(W,elizabeth)" and G3, "female(W). --- It works first on G2, "child(W,elizabeth)". --- It finds the rule, "child(X,Y) :- parent(Y,X)." --- So it generates the goal G4: "parent(elizabeth,W)" --- G4 succeeds with W = charles --- So G2 succeeds with W = charles --- So we try that for G3; --- With W = charles, G3 is "female(charles)", which fails. --- So we go back to G4, and look for another solution. --- The next solution to G4 is W = anne --- So we try that with G3 --- With W = anne, G3 is "female(anne)", which succeeds. --- So G1 succeeds with W = anne. | ?- daughter(anne,X). X = elizabeth ; X = philip ; no | ?- son(X,Y). X = charles Y = elizabeth ; X = charles Y = philip ; X = andrew Y = elizabeth ; X = andrew Y = philip yes --- Multiple rules | ?- [user]. sibling(X,Y) :- parent(Z,X), parent(Z,Y). /* A sibling is someone with the same parent */ close-relation(X,Y) :- child(X,Y). close-relation(X,Y) :- sibling(X,Y). close-relation(X,Y) :- parent(X,Y). /* A close relation is either a child, or a sibling, or a parent. */ ^D user consulted ... --- When more than one rule is given for a goal, Prolog tries the --- various rules in the given order. | ?- close-relation(anne,charles). yes --- The second rule succeeds. | ?- close-relation(X,charles). X = william ; X = harry ; X = charles ; X = charles ; X = anne ; X = anne ; X = andrew ; X = andrew ; X = elizabeth ; X = philip ; no --- Prolog first goes through the answers given by the "child" --- rule, then the answers given by the "sibling" rule, then the --- answers given by the "parent" rule. --- The goal ``sibling(charles,X)'' succeeds twice for each sibling of --- Charles, as well as for himself, once for their common parent Elizabeth --- and once for their common parent Philip. --- Recursion | ?- [user]. ancestor(X,X). ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y). ^D user consulted ... --- The ancestor relationship is defined recursively in two rules: --- (Base case) Every man is his own ancestor. --- (Recursive case). If X is a parent of an ancestor of Y, then X --- is an ancestor of Y. --- Note: A literal with variables and no body, such as "ancestor(X,X)", --- is essentially a statement that the form is true for all values of --- the variable; that is, for any X, "ancestor(X,X)" is true. | ?- ancestor(charles,charles). yes --- The query matches the base rule "ancestor(X,X)". | ?- ancestor(philip,charles). yes --- The goal G1 "ancestor(philip,charles)" does not match the base --- rule, so Prolog goes onto the second rule --- "ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y)" --- and generates the two goals: G2, "parent(philip,Z)" --- and G3, "ancestor(Z,charles)" --- G2 succeeds with Z = charles. --- Substituting Z = charles into G3 gives "ancestor(charles,charles)" --- which succeeds. | ?- ancestor(philip,W). W = philip ; W = charles ; W = william ; W = harry ; W = anne ; W = andrew ; no --- Given the goal G1: "ancestor(philip,W)", --- Prolog matches it with the rule "ancestor(X,X)" under the --- binding X = W = philip, so it succeeds with W = philip. --- When the user asks it for another solution it tries the next --- rule, "ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y). --- So it generates the two goals: G2, "parent(philip,Z)" --- and G3, "ancestor(Z,W)". --- The first solution to G2 is Z = charles. --- This is substituted in G3, giving the goal "ancestor(charles,W)". --- Prolog matches this with the rule "ancestor(X,X)", which --- succeeds under the binding X = W = charles. --- So G1 reports success with the binding W = charles. --- When the user asks for a new solution, Prolog tries to solve G3 --- using the recursive rule. --- So it generates the two goals G4, "parent(charles,Z)" and --- G5, "ancestor(Z,W)" --- The first solution to G4 is Z = william. --- This is substituted in G5, giving the goal "ancestor(william,W)" --- Prolog matches this with the rule "ancestor(X,X)", which succeeds --- under the binding X = W = william. --- So G1 reports success with the binding W = william. --- When the user asks for a new solution, Prolog tries to --- solve G5 using the recursive rule for ancestor. --- So it generates the two goals: G6, "parent(william,Z)" --- and G7, "ancestor(Z,W)." --- G6 fails. william is not the parent of anyone. --- Therefore there are no more solutions to G5. --- So Prolog looks for another solution to G4. --- The next solution to G4 is Z = harry. --- ... and so on ... --- Note two things. First, our definition of "ancestor" --- will be terrible for answering queries like "ancestor(W,william)". --- Second, the order of the clauses, and of the literals in the --- clauses is very important. If we had made the definition --- ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y). --- ancestor(X,X). --- then Prolog would start by looking at the most remote ancestors, --- and work its way down to the most immediate ancestors. --- If the defintion had been --- ancestor(X,X). --- ancestor(X,Y) :- ancestor(Z,Y), parent(X,Z). --- Prolog would go into an infinite loop. --- Structures | ?- [user]. | familyTree(X,l(X)). familyTree(X,t(X,MTREE,FTREE)) :- mother(M,X), father(F,X), familyTree(M,MTREE), familyTree(F,FTREE). ^D | user consulted ... yes | ?- familyTree(elizabeth, TREE). TREE = l(elizabeth) ; no | ?- familyTree(charles,TREE). TREE = l(charles) ; TREE = t(charles,l(elizabeth),l(philip)) ; no | ?- familyTree(harry,TREE). TREE = l(harry) ; TREE = t(harry,l(diana),l(charles)) ; TREE = t(harry,l(diana),t(charles,l(elizabeth),l(philip))) ; no | ?- [user]. familyTree(X,t(X,MTREE,FTREE)) :- mother(M,X), father(F,X), familyTree(M,MTREE), familyTree(F,FTREE). familyTree(X,l(X)). ^D user reconsulted ... | ?- familyTree(harry, TREE). TREE = t(harry,l(diana),t(charles,l(elizabeth),l(philip))) ; TREE = t(harry,l(diana),l(charles)) ; TREE = l(harry) ; no --- Queries with the equals sign cause structures to be matched --- This matching is called unification. | ?- oo(sam, pp(X,fred,Y)) = oo(Z, pp(Z, W, rr(george, W))). W = fred X = sam Y = rr(george,fred) Z = sam yes --- Lists --- --- A list is type of structure. The elements of a list are written --- between brackets, separated by commas. The list constructor --- [ X | Y ] means that X is the first element of the list and Y is --- the rest of the elements. More than one thing can come before the --- bar. For example [X, Y, Z | REST] means that X is the 1st element, --- Y is the 2nd, Z is the 3rd, and REST are the rest. [] is the list --- with no elements. --- Lists can contain sublists or other structures as elements. | ?- [X, Y, Z] = [alpha, beta, gamma]. X = alpha Y = beta Z = gamma yes | ?- [FIRST | REST] = [moby-dick, peter-rabbit, winnie-the-pooh]. FIRST = moby-dick REST = [peter-rabbit, winnie-the-pooh] yes | ?- [X, Y | REST] = [[a, b, c], 1, 2, tree(sam, sarah, sid)]. X = [a, b, c] Y = 1 REST = [2, tree(sam, sarah, sid)] yes | ?- [X, Y, Y, a] = [Z, b, W, Z]. X = a Y = b Z = a W = b yes | ?- [X, Y, Z] = [A, A, q]. X = A Y = A Z = q yes ---- Be careful not to do the following | ?- [X, tree(X)] = [Y, Y]. Goes into an infinite loop --- You have to Cntl-C out of it. | ?- [user]. /* X is a member of L if either X is the first element of L, or if X is a member of the tail of L. Note that "member(X,L)" is already defined in Prolog, so we name this "member1". */ | member1(X,L) :- L = [X | REST]. | member1(X,L) :- L = [Y | REST], member1(X, REST). | ^D | user consulted ... | ?- member1(a, [a, b, c]). yes | ?- member1(b, [a, b, c]). yes | ?- member1(o, [a, b, c]). no | ?- member1(a, [[a, b], c]). no | ?- member1(X, [a, b, c]). X = a ; X = b ; X = c ; no | ?- member1(a,L). L = [a | _6] ; L = [_5, a | _10] ; L = [_5, _9, a | _14] yes | ?- [-user]. | /* A more elegant way to write the member predicate. The equalities | are collapsed into the forms of the predicates, and the anonymous | variable _ is used for variables whose value does not matter | */ | member1(X,[X|_]). | member1(X,[_|REST]) :- member1(X,REST). | | /* list_fathers(L, FATHERS) is true if everyone in FATHERS is the | father of the corresponding person in L. Again, we use a recursive | definition. If L is the null list, then FATHERS is the null list. | Otherwise the head of FATHERS is the father of the head of L, and | the tail of FATHERS is list_fathers of the tail of L. */ | | list_fathers(L, FATHERS) :- L = [], FATHERS = []. | list_fathers(L, FATHERS) :- | L = [FIRSTL | RESTL], | FATHERS = [FIRSTF | RESTF], | father(FIRSTF, FIRSTL), | list_fathers(RESTL, RESTF). ^D user reconsulted ... | ?- list_fathers([charles, harry, anne], [philip, charles, philip]). yes | ?- list_fathers([charles, harry, anne], L). L = [philip, charles, philip] ; no | ?- list_fathers(L, [philip, charles, philip]). L = [charles, william, charles] ; L = [charles, william, anne] ; L = [charles, william, andrew] ; L = [charles, harry, charles] yes | ?- list_fathers([X, anne, harry], [philip | REST]). X = charles REST = [philip, charles] yes | ?- [-user]. | /* A more elegant formulation of list_fathers */ | list_fathers([], []). | list_fathers([FIRST |REST], [FIRSTF| RESTF]) :- | father(FIRSTF,FIRST), list_fathers(REST,RESTF). | | /* append(L, M, N) means that N is the result of appending L and M | together. We use recursion on the argument L. If the null list | is appended to M, then the result is M. If [X | RESTL] is appended | to M giving N, then the first element of N is X, and the rest of | N is the result of appending RESTL to M. */ | | append(L, M, N) :- L = [], M = N. | append(L, M, N) :- | L = [X | RESTL], N = [X | RESTN], append(RESTL, M, RESTN). | ^D user reconsulted ... | ?- append([a,b,c], [d,e,f], [a,b,c,d,e,f]). yes | ?- append([a,b,c], [d,e,f], N). N = [a,b,c,d,e,f] yes | ?- append([a,b,c], M, [a,b,c,d,e,f]). M = [d,e,f] yes | ?- append(L, M, [a,b,c,d,e,f]). L = [] M = [a,b,c,d,e,f] ; L = [a] M = [b,c,d,e,f] ; L = [a,b] M = [c,d,e,f] yes | ?- [-user]. | /* A more elegant formulation of append */ | append([], M, M). | append([X|REST], M, [X|RESTN]) :- append(REST, M, RESTN). | ^D --- Useful debugging functions. trace. -- Traces all predicate calls and exits. spy . -- Traces all calls and exits from the specified predicate. For instance, | ?- spy member. will cause all calls to member to be traced. Prolog will stop and ask you for an action at each call. You can get a list of all possible actions by typing a question mark. Usually, you will just want to hit carriage return, to have Prolog proceed to the next call. listing() prints out all clauses with the predicate. For example | ?- listing(member). prints out member(_3, [_3 | _12 ]). member(_3 , [_10 | _12]) :- member(_3, _12). Note that all variable names are replaced by _number. --- Arithmetic --- Prolog has integer and real arithmetic. Arithmetic works by --- function evaluation, as in ordinary languages, rather than --- by predicates. To assign the value of a term T to a variable X, --- write "X is T". For example, "A is B + 1", "X is 3" --- "WW is (A + B) / log(2)", etc. Note that any variables in the --- must have been instantiated to a numeric value; otherwise the --- "is" fails. If arithmetic relations such as == (numeric equality), --- >, <, >=, =<, are used to compare two terms, both terms must --- be instantiated to a numeric value. --- --- A variable can only be assigned once; "N is N+1" will always fail. --- Note: All of your functions have to be defined as predicates. You --- cannot define an evaluable function. --- Arithmetic expressions cannot be the head of a clause. | ?- X is 1, Y is X + X, Z is Y * Y. X = 1 Y = 2 Z = 4 yes | ?- X is 1, Y is X + X, Y > X. X = 1 Y = 2 yes | ?- X is 1, Y is X + X, X > Y. no | ?- X is 1, Y > X. | Error in arithmetic expression: not a number. no | ?- [user]. | factorial(0,1). | factorial(N,FACT) :- M is N - 1, factorial(M,MF), FACT is MF * N. | ^D user consulted ... | ?- factorial(5,F). F = 120 yes | ?- [user]. | nthElement([X|_], 1, X). | nthElement([_|REST],N,X) :- N > 1, M is N-1, nthElement(REST,M,X). | ^D user consulted ... | ?- nthElement([a,b,c,d,e,f], 4, X). X = d yes | ?- nthElement(L,3,a). L = [_14,_11,a|_5] ; no --- Not --- If you have a goal of the form "\+", then Prolog tries --- to satisfy the literal. If the literal fails, then the goal --- "\+ ..." succeeds. | ?- [user]. | unparent(X,Y) :- \+parent(X,Y). | ^D user consulted ... | ?- unparent(charles,anne). yes | ?- unparent(philip,charles). no. --- When \+ is used on a literal with variables, the wrong thing --- happens. Prolog does not return a value for which the statement is --- false; rather it checks to see if there are any values for which --- the statement is true, and, if there are any such values, the not --- fails. Even when the goal succeeds, no binding is returned for the --- variable. | ?- unparent(X,charles). no --- The goal "parent(X,charles)" succeeds with X = elizabeth. Hence --- the goal "not(parent(X,charles))" fails | ?- unparent(X,philip). X = _0 yes --- Example where "not" is needed to suppress invalid solutions on --- backtracking. | ?- [user]. | /* intersect(L,M,I) computes the intersection of the two lists L and M | and gives the value in I */ | | intersect([],M,[]). | intersect([X|L],M,[X|I]) :- member(X,M), intersect(L,M,I). | intersect([_|L],M,I) :- intersect(L,M,I). | ^D --- This definition gives the correct solution on the first try, but --- then backtracks to partial solutions | ?- intersect([a,b,c,d], [d,f,e,b], I). I = [b,d] ; I = [b] ; I = [d] ; I = [] no. | ?- [-user]. | | intersect([],M,[]). | intersect([X|L],M,[X|I]) :- member(X,M), intersect(L,M,I). | intersect([X|L],M,I) :- \+member(X,M), intersect(L,M,I). | ^D | ?- intersect([a,b,c,d], [d,f,e,b], I). I = [b,d] ; no --- Cut Operator. --- The cut operator, denoted by an exclamation point !, is used to --- control backtracking. If the cut operator occurs in the tail of --- a clause, then, if the clause is invoked, and the goals in the --- clause becore the cut succeed, the cut succeeds immediately, and --- the next goal is tried. On backtracking, if Prolog backtracks to --- the cut operator, then the goal which invoked the clause fails --- immediately. The preceding literals in the tail are not tried --- again, and no other clauses are tried for the invoking goal. --- There are three major uses for the cut operator. The first is --- to signal Prolog that the right rule in a given case has been --- reached, and that no other rules need be tried. This can be used --- to create the equivalent of a "case" statement out of several --- clauses, by making sure that only one of them is tried for each --- goal. This is particularly useful when there are a small number of --- exceptions to a general rule. Enumerate the exceptions first, --- with cut operators. [user]. | locomotion(X,swim) :- inst(X, whale), !. | locomotion(X,swim) :- inst(X, seal), !. | locomotion(X,fly) :- inst(X, bat), !. | locomotion(X,run) :- inst(X, mammal), !. | locomotion(X,run) :- inst(X, ostrich), !. | locomotion(X,swim) :- inst(X, penguin), !. | locomotion(X,fly) :- inst(X, bird), !. | locomotion(X,swim) :- inst(X, fish). --- Now, we add some particular animals and categories | inst(wally,whale). | inst(cathy,cow). | inst(X,mammal) :- inst(X,whale). | inst(X,mammal) :- inst(X,cow). EOT | ?- locomotion(cathy, L). L = run ; no. | ?- locomotion(wally, L). L = swim ; no. --- Without the cut mark, the query for "wally" would have backtracked and --- found the second solution L = run, because wally is also a mammal. --- A more subtle example of the same thing is in the intersection --- predicate: | intersect([], M, []). | intersect([X | RL], M, [X | RI]) :- | member(X,M), !, intersect(RL, M, RI). | intersect([_ | RL], M, I) :- | intersect(RL, M, I). --- Here the cut operator in the second rule signals Prolog that, if --- member(X,M) succeeds, then this rule, which makes X a member of I, --- should be used, and that the third rule, which leaves X --- out of I, should not be invoked, even on backtracking. --- Note that, in both these cases, we could have achieved the same --- effect using "\+" with rules like | locomotion(X,run) :- | \+inst(X,whale), \+inst(X,seal), \+inst(X,bat)), | inst(X,mammal). --- or | intersection([X | RL], M, RI) :- | \+member(X,M), intersection(RL, M, I). --- but these are substantially inefficient. --- Sometimes you want to do this just for efficiency. | /* mult_list(L,N) returns N as the product of all the number in L. | For example, mult_list([4,5,6],N) returns N=120. If 0 is encountered, | then return 0 immediately without proceeding. */ | mult_list([],1). | mult_list([0 | _], 0) :- !. | mult_list([X |RL], N) :- | mult_list(RL,N1), N is X * N1. | --- Cut/Fail --- If we want to signal particular cases where the goal cannot be --- satisfied, we test for those case, use the cut operator, and then --- fail. | can_fly(X) :- inst(X,ostrich), !, fail. | can_fly(X) :- inst(X,penguin), !, fail. | can_fly(X) :- dead(X), !, fail. | can_fly(X) :- inst(X, bird). | Use cut to stop backtracking after finding first solution. | /* factorize(N,FACTORS) returns FACTORS as the list of prime factors | of N */ | factorize(1, []) :- !. | factorize(N, [FACT | REST_FACTS]) :- | find_factor(N,FACT,2), N1 is N/FACT, factorize(N1, REST_FACTS). | /* find_factor(N,FACT,LOW) returns the smallest factor of N greater | than or equal to LOW. */ | find_factor(N,FACT,FACT) :- R is N mod FACT, R = 0, !. | find_factor(N,FACT,LOW) :- | N1 is LOW+1, N1 <= N, find_factor(N,FACT,N1). --- Side effects. --- assertz(CLAUSE) asserts a clause at the end of the database. --- asserta(CLAUSE) asserts a clause at the beginning of the database. --- retract(CLAUSE) retracts a clause unifying with CLAUSE. --- You can use this to get the effect of global variables. | assign(V,VALUE) :- | ( retract(value_of(V,_)); true), | asserta(value_of(V,VALUE)). | ?- assign(x,1). yes | ?- value_of(x,VALUE). VALUE = 1 yes | ?- assign(x,2). yes | ?- value_of(x,VALUE). VALUE = 2 yes --- IMPORTANT: Keep this style of programming to an ABSOLUTE MINIMUM. --- Using backtracking for looping with side-effects. | display_children(X) :- parent(X,C), nl, write(C), fail. | display_children(_). | ?- display_children(philip). charles anne andrew yes | ?- [user]. | copy_children(X,Y) :- parent(X,C), assertz(parent(Y,C)), fail. | copy_children(_,_). | ^D | ?- copy_children(philip,moe). yes | ?- display_children(moe). charles anne andrew yes