Logic Programming Lecture 3: Recursion, lists, and data structures
Jan 12, 2016
Logic Programming
Lecture 3: Recursion, lists, and data structures
James Cheney Logic Programming October 8, 2009
Outline for today
•Recursion - proof search behavior and practical concerns
•List processing
•Programming with terms as data structures
James Cheney Logic Programming October 8, 2009
Recursion
•So far we've (mostly) used nonrecursive rules
•These are limited:
• can't define transitive closure
• e.g. ancestor
•not Turing-complete
James Cheney Logic Programming October 8, 2009
Recursion (1)
•Nothing to it:
ancestor(X,Y) :- parent(X,Y).
ancestor(X,Y) :- parent(X,Z),
ancestor(Z,Y).
•Just use predicate as a goal.
•Easy, right?
James Cheney Logic Programming October 8, 2009
Depth first search, revisited
•Prolog tries rules in depth-first order
•no matter what
• Even if there is an "obvious" solution using later clauses!
p :- p.
p.
•will always loop on first rule.
James Cheney Logic Programming October 8, 2009
Recursion (2)
•Rule order can matter.
ancestor2(X,Y) :- parent(X,Z),
ancestor2(Z,Y).
ancestor2(X,Y) :- parent(X,Y).
This may be less efficient (tries to find longest path first)
Heuristic: try non-recursive rules first.
James Cheney Logic Programming October 8, 2009
Rule order mattersancestor(a,b)ancestor(a,b)
parent(a,Z),ancestor(Z,b) parent(a,Z),ancestor(Z,b) parent(Z,Y)parent(Z,Y)
Z = b
ancestor(b,b)ancestor(b,b)
parent(a,b).parent(b,c).
parent(a,b)parent(a,b)
dondonee
James Cheney Logic Programming October 8, 2009
Recursion (3)
•Goal order can matter.
ancestor3(X,Y) :- parent(X,Y).
ancestor3(X,Y) :- ancestor3(Z,Y),
parent(X,Z).
This will list all solutions, then loop.
James Cheney Logic Programming October 8, 2009
Recursion (4)
•Goal order can matter.
ancestor4(X,Y) :- ancestor4(Z,Y),
parent(X,Z).
ancestor4(X,Y) :- parent(X,Y).
This will always loop!
Heuristic: try non-recursive goals first.
James Cheney Logic Programming October 8, 2009
Goal order mattersancestor(X,Y)ancestor(X,Y)
ancestor(X,Z), parent(Z,Y)ancestor(X,Z), parent(Z,Y)
ancestor(X,W), parent(W,Z)ancestor(X,W), parent(W,Z), parent(Z,Y), parent(Z,Y)
ancestor(X,V), parent(V,W)ancestor(X,V), parent(V,W), parent(W,Z), parent(Z,Y), parent(W,Z), parent(Z,Y)
...ancestor(X,U), parent(U,V)ancestor(X,U), parent(U,V), parent(V,W), parent(W,Z), parent(Z,Y), parent(V,W), parent(W,Z), parent(Z,Y)
James Cheney Logic Programming October 8, 2009
Recursion and terms
•Terms can be arbitrarily nested
•Example: natural numbers
nat(z).
nat(s(N)) :- nat(N).
•To do interesting things we need recursion
James Cheney Logic Programming October 8, 2009
Addition and subtraction
•Example: addition
add(z,N,N).
add(s(N),M,s(P)) :- add(N,M,P).
• Can run in reverse to find all M,N with M+N=P
• Can use to define leq
leq(M,N) :- add(M,_,N).
James Cheney Logic Programming October 8, 2009
Multiplication
•Can multiply two numbers:
multiply(z,N,z).
multiply(s(N),M,P) :-
multiply(N,M,Q), add(M,Q,P).
square(M) :- multiply(N,N,M).
James Cheney Logic Programming October 8, 2009
List processing
•Recall built-in list syntax
list([]).
list([X|L]) :- list(L).
•Example: list append
append([],L,L).
append([X|L],M,[X|N]) :- append(L,M,N).
James Cheney Logic Programming October 8, 2009
Append in action
•Forward direction
?- append([1,2],[3,4],X).
•Backward direction
?- append(X,Y,[1,2,3,4]).
James Cheney Logic Programming October 8, 2009
Mode annotations•Notation append(+,+,-)
• "if you call append with first two arguments ground then it will make the third argument ground"
• Similarly, append(-,-,+)
• "if you call append with last argument ground then it will make the first two arguments ground"
•Often used in documentation
• "?" annotation means either + or -
James Cheney Logic Programming October 8, 2009
List processing (2)•When is something a member of a
list?
mem(X,[X|_]).
mem(X,[_|L]) :- mem(X,L).
•Typical modes
mem(+,+)
mem(-,+)
James Cheney Logic Programming October 8, 2009
List processing(3)
•Removing an element of a list
remove(X,[X|L],L).
remove(X,[Y|L],[Y|M]) :- remove(X,L,M).
•Typical mode
remove(+,+,-)
James Cheney Logic Programming October 8, 2009
List processing (4)
•Zip, or "pairing" corresponding elements of two lists
zip([],[],[]).
zip([X|L],[Y|M],[(X,Y)|N]) :- zip(L,M,N).
•Typical modes:
zip(+,+,-).
zip(-,-,+). % "unzip"
James Cheney Logic Programming October 8, 2009
List flattening• Write predicate flatten/2
• Given a list of (lists of ..) lists
• Produces a list containing all elements in order
James Cheney Logic Programming October 8, 2009
List flattening• Write predicate flatten/2
• Given a list of (lists of ..) lists
• Produces a list containing all elements in order
flatten([],[]).
flatten([X|L],M) :- flatten(X,Y1),
flatten(L,Y2),
append(Y1,Y2,M).
flatten(X,[X]) :- \+(list(X)).
Negation as Negation as failure failure
(more next week)(more next week)Requires mode Requires mode
(+,-)(+,-)
James Cheney Logic Programming October 8, 2009
Records/structs• We can use terms to define data structures
pb([entry(james,'123-4567'),...])
• and operations on them
pb_lookup(pb(B),P,N) :-
member(entry(P,N),B).
pb_insert(pb(B),P,N,pb([entry(P,N)|B])).
pb_remove(pb(B),P,pb(B2)) :-
remove(entry(P,_),B,B2).
James Cheney Logic Programming October 8, 2009
Trees
•We can define (binary) trees with data:
tree(leaf).
tree(node(X,T,U)) :- tree(T), tree(U).
James Cheney Logic Programming October 8, 2009
Tree membership
•Define membership in tree
mem_tree(X,node(X,T,U)).
mem_tree(X,node(Y,T,U)) :-
mem_tree(X,T) ;
mem_tree(X,U).
James Cheney Logic Programming October 8, 2009
Preorder traversal•Define preorder
preorder(leaf,[]).
preorder(node(X,T,U),[X|N]) :-
preorder(T,L),
preorder(U,M),
append(L,M,N).
•What happens if we run this in reverse?
James Cheney Logic Programming October 8, 2009
Next time
•Nonlogical features
•Expression evaluation
• I/O
• "Cut" (pruning proof search)
•Negation-as-failure
James Cheney Logic Programming October 8, 2009
Further reading
•LPN, ch. 3-4