The Current Topic: Prolog Announcements Using Not Instead
Total Page:16
File Type:pdf, Size:1020Kb
The current topic: Prolog Announcements • Term Test 2 has been marked. ! Introduction – Handed back at the end of class today. ! Object-oriented programming: Python – The deadline for submitting a re-mark request is the end of class, Friday November 28th. Make sure you understand the posted solutions before ! Functional programming: Scheme submitting a re-mark request. ! Python GUI programming (Tkinter) – Average: 68.4% ! Types and values • Logic programming: Prolog ! Introduction ! Rules, unification, resolution, backtracking, lists. ! More lists, math, structures. ! More structures, trees, cut. – Next up: Negation. • Syntax and semantics • Exceptions Fall 2008 Prolog: Negation 1 Fall 2008 Prolog: Negation 2 Using not instead of cut to avoid wrong answers Using not for inequality • Example: • Prolog has a not operator, but its behaviour is more subtle than in other crispy(snap). languages. crispy(crackle). crispy(pop). • Example: Replacing a cut with not: breakfast(A,B,C) :- crispy(A), crispy(B), crispy(C). – With cut: ?- breakfast(A,B,C). A :- B, !, C. A = snap A :- D. B = snap – With not: C = snap ; A :- B, C. A :- not(B), D. A = snap B = snap C = crackle ; • Observe that not can be more cumbersome than cut. ... – repetitive if-then-else • But we really want A, B, and C to be different from each other. Fall 2008 Prolog: Negation 3 Fall 2008 Prolog: Negation 4 Using not for inequality Negation in Prolog crispy(snap). • not(B) can also be written as \+ B. crispy(crackle). – And not(X=Y) can also be written as X \= Y. crispy(pop). breakfast(A,B,C) :- crispy(A), crispy(B), crispy(C), not(A=B), • The goal \+ X succeeds iff X fails. not(A=C), not(B=C). • Examples: ?- breakfast(A,B,C). ?- \+ member(b, [a,b,c]). A = snap No B = crackle ?- \+ member(x, [a,b,c]). C = pop ; Yes ?- \+ member(X, [a,b,c]). A = snap No B = pop C = crackle ; ... Fall 2008 Prolog: Negation 5 Fall 2008 Prolog: Negation 6 Negation in Prolog Negation as failure ?- \+ member(X, [a,b,c]). • Prolog assumes that if it can't prove an assertion, then the assertion is No false. – And Prolog assumes that if it can prove an assertion, then the assertion is true. • It might look like this query is asking "Does there exist an X for which member(X, [a,b,c]) does not succeed?". • This is the "closed world assumption": in the universe of facts Prolog – We know there are lots of values of X for which member(X, [a,b,c]) does not knows about, failure to prove is proof of failure. succeed. – But if we know something Prolog doesn't, this can lead to surprises: things that – But that's not what negation means in Prolog. Prolog thinks are false when we know they're true, and the opposite. – There exists X for which member(X, [a,b,c]) succeeds. – Example: – So then \+ member(X, [a,b,c]) fails. university(uoft). ?- university(york). No ?- \+ university(york). Yes Fall 2008 Prolog: Negation 7 Fall 2008 Prolog: Negation 8 Be careful with negation Tracing negation sad(X) :- \+ happy(X). ?- sad(michael). • Let's look at how Prolog answers sad(Someone).: happy(X) :- beautiful(X), rich(X). No rich(bill). ?- sad(jim). ?- sad(Someone). beautiful(michael). Yes Call: (7) sad(_G283) ? creep rich(michael). ?- sad(Someone). beautiful(cinderella). No Call: (8) happy(_G283) ? creep Call: (9) beautiful(_G283) ? creep ?- sad(bill). • Isn't anyone sad? Exit: (9) beautiful(michael) ? creep Call: (9) rich(michael) ? creep Yes • No, that just means that it's Exit: (9) rich(michael) ? creep ?- sad(cinderella). not true we can't find anyone Exit: (8) happy(michael) ? creep Yes happy. Fail: (7) sad(_G283) ? creep – In other words, there exists someone who is happy. No Fall 2008 Prolog: Negation 9 Fall 2008 Prolog: Negation 10 Set overlap What does that mean? • Write a predicate overlap(S1, S2) that succeeds if lists S1 and S2 have a common element. Then write a predicate disjoint(S1, S2) ?- disjoint([a,b,d], S). that succeeds if S1 and S2 have no common element. No overlap(S1, S2) :- member(X, S1), member(X, S2). • The query should mean "can you find a list S that is disjoint from the list disjoint(S1, S2) :- \+ overlap(S1, S2). [a,b,d] (and if so what is it)?". • Obviously there are many such sets, so why "No"? ?- overlap([a,b,c], [c,d,e]). • Answer: because Prolog succeeded in finding a set that did overlap with Yes S, so it announced failure of the original query. ?- disjoint([a,b,c], [c,d,e]). No ?- overlap([a,b,d], S). ?- overlap([a,b,c], [d,e,f]). S = [a|_G226] ; No S = [_G225, a|_G229] ; ?- disjoint([a,b,c], [d,e,f]). S = [_G225, _G228, a|_G232] ; Yes ... ?- disjoint([a,b,d], S). No Fall 2008 Prolog: Negation 11 Fall 2008 Prolog: Negation 12 Safe use of negation Double-negation doesn't "cancel out" • The goal not(G) is safe if either: • In other languages, not(not(<expression>)) is equivalent to – G is fully instantiated when not(G) is processed, or <expression>. – G has uninstantiated variables, but they don't appear anywhere else in the clause. – But not in Prolog. • Safe example: ?- member(X,[a,b,c]). childlessMan(X) :- male(X), \+ parent(X,Y). X = a ; – X is instantiated in male(X), and Y isn't used elsewhere. X = b ; X = c ; No • Unsafe example: childlessMan(X) :- \+ parent(X,Y), male(X). ?- not(not(member(X,[a,b,c]))). – X is not instantiated before the negation, and is used elsewhere. X = _G166 ; No • If necessary, add a precondition to warn the programmer. – recall that +Var means that Var must be instantiated. % disjoint(+S1, +S2) succeeds if... disjoint(S1, S2) :- \+ overlap(S1, S2). – When the precondition is satisfied, this negation is safe. Fall 2008 Prolog: Negation 13 Fall 2008 Prolog: Negation 14 Double-negation doesn't "cancel out" fail • The fail predicate fails immediately. Example: ?- not(not(member(X,[a,b,c]))). X = _G166 ; p(X) :- fail. No ?- p(csc326). • Why is X uninstantiated in this example? No – Since member(X, [a,b,c]) succeeds (by instantiating X to, say, a), not(member(X, [a,b,c])) fails. • We can use fail to state that something is false. – When a goal fails, the variables it instantiated get uninstantiated. So X gets uninstantiated. – But since not(member(X, [a,b,c])) fails, not(not(member(X, [a,b,c]))) succeeds. Fall 2008 Prolog: Negation 15 Fall 2008 Prolog: Negation 16 fail fail • Example: We want to represent "Colbert does not like bears (regardless • We need to add a cut to prevent other rules from being tried after the of whatever else he likes)." first rule reaches fail. – One solution: Add "not(bear(X))" to every rule describing what Colbert likes. – Second attempt: For example: bear(yogi). likes(colbert, X) :- animal(X), not(bear(X)). cat(tom). likes(colbert, X) :- toy(X), not(bear(X)). animal(yogi). likes(colbert, X) :- livesInArctic(X), not(bear(X)). animal(tom). ... likes(colbert, X) :- bear(X), !, fail. – Let's try to use fail instead. likes(colbert, X) :- animal(X). – First attempt: bear(yogi). ?- likes(colbert, yogi). animal(yogi). No likes(colbert, X) :- bear(X), fail. ?- likes(colbert, tom). likes(colbert, X) :- animal(X). Yes ?- likes(colbert, X). ?- likes(colbert, yogi). No Yes – Downside: This solution only works when X is instantiated. Fall 2008 Prolog: Negation 17 Fall 2008 Prolog: Negation 18 fail Defining "not" using cut and fail • Another example: Define a predicate different(X, Y) that succeeds • We can define the not predicate as follows: if X and Y don't unify. not(X) :- X, !, fail. different(X, Y) :- X=Y, !, fail. not(_). different(_, _). • (To test this out, use a name other than "not", since Prolog won't let ?- different(a, b). you redefine the built-in "not"). Yes ?- different(a, a). No • Notice that the above definition is equivalent to: different(X, Y) :- not(X=Y). Fall 2008 Prolog: Negation 19 Fall 2008 Prolog: Negation 20 fail Inefficiency in bstmem • Recall the original version of bstmem(Tree, X): [trace] ?- bstmem(node(5, node(3,empty,empty), emtpy), 1). bstmem(node(X, _, _), X). Call: (8) bstmem(node(5, node(3, empty, empty), emtpy), 1) ? bstmem(node(K, L, _), X) :- X < K, bstmem(L, X). creep ^ Call: (9) 1<5 ? creep bstmem(node(K, _, R), X) :- X > K, bstmem(R, X). ^ Exit: (9) 1<5 ? creep Call: (9) bstmem(node(3, empty, empty), 1) ? creep • Recall that this version was inefficient. ^ Call: (10) 1<3 ? creep ^ Exit: (10) 1<3 ? creep Call: (10) bstmem(empty, 1) ? creep Fail: (10) bstmem(empty, 1) ? creep Redo: (9) bstmem(node(3, empty, empty), 1) ? creep ^ Call: (10) 1>3 ? creep ^ Fail: (10) 1>3 ? creep Redo: (8) bstmem(node(5, node(3, empty, empty), emtpy), 1) ? creep ^ Call: (9) 1>5 ? creep ^ Fail: (9) 1>5 ? creep No Fall 2008 Prolog: Negation 21 Fall 2008 Prolog: Negation 22 fail Tracing the new bstmem • We solved the inefficiency illustrated on the previous slide as follows: [trace] ?- bstmem(node(5, node(3,empty,empty), emtpy), 1). Call: (8) bstmem(node(5, node(3, empty, empty), emtpy), 1) ? creep bstmem(node(X, _, _), X). ^ Call: (9) 1<5 ? creep bstmem(node(K, L, _), X) :- X < K, !, bstmem(L, X). ^ Exit: (9) 1<5 ? creep bstmem(node(K, _, R), X) :- X > K, bstmem(R, X). Call: (9) bstmem(node(3, empty, empty), 1) ? creep ^ Call: (10) 1<3 ? creep ^ Exit: (10) 1<3 ? creep • What if we try to instead solve this inefficiency by using fail: Call: (10) bstmem(empty, 1) ? creep Call: (11) fail ? creep bstmem(empty,_) :- !, fail.