Declarative Programming Lists in PROLOG Autumn 2014 Example - Fibonacci numbers Fibonacci numbers are defined as follows: F(i) = 0, 1, F(i–1) + F(i – 2), if i = 0 if i = 1 if i > 1 Example - Fibonacci numbers Fibonacci numbers are defined as follows: F(i) = 0, 1, F(i–1) + F(i – 2), if i = 0 if i = 1 if i > 1 fibonacci(0,0). fibonacci(1,1). fibonacci(X,R) :- X1 is X–1, X2 is X–2, fibonacci(X1,R1), fibonacci(X2,R2),R is R1+R2. Example - Fibonacci numbers We can try to write a predicate that computes both values F(i) and F(i – 1) fibonacci(1,1,0). fibonacci(X,R1,R2) :- X1 is X–1,fibonacci(X1,R2,R3),R1 is R2+R3. Example - Fibonacci numbers If we want, we can now add a predicate just for computing of F(i) fibonacci(1,1,0). fibonacci(X,R1,R2) :- X1 is X–1,fibonacci(X1,R2,R3),R1 is R2+R3. fibonacci(0,0). fibonacci(X,R) :- fibonacci(X,R,R1). Example - Fibonacci numbers What, if we want something like this: S(i) = 0, 1, i*S(0)+ (i–1)*S(1)+...+2S(i–1), if i = 0 if i = 1 if i > 1 Example - Fibonacci numbers What, if we want something like this: S(i) = 0, 1, i*S(0)+ (i–1)*S(1)+...+2S(i–1), if i = 0 if i = 1 if i > 1 A predicate that computes all the values S(0)...S(i) at once could be useful... Lists - the idea nil list(a,nil) list(a,list(b,nil)) list(a,list(b,list(c,nil))) ... represents the empty list represents list a represents list a,b represents list a,b,c Example - list of Fibonacci numbers fibonacci(0,list(0,nil)). fibonacci(1,list(1,list(0,nil))). fibonacci(X,list(R, list(R1,list(R2,Z)))) :fibonacci(X1,list(R1,list(R2,Z))), R is R1+R2. X1 is X–1, Lists - predefined notation [] .(a,[]) .(a,.(b,[])) .(a,.(b,.(c,[]))) ... represents the empty list represents list a represents list a,b represents list a,b,c Lists - predefined notation There is also a special shortcut notation for lists in PROLOG .(a,.(b,.(c,[]))) can also be written as [a,b,c] Lists - useful operations Often it is useful to divide non-empty list into the first element (head) and the remaining list (tail) head(.(H,_),H). tail(.(_,T),T). Lists - useful operations There are special predicate “|” that does not require the use of “.” notation head([H|_],H). tail([_|T],T). Lists - useful operations Any fixed number of initial elements can be accessed first_7([F1,F2,F3,F4,F5,F6,F7|_],F1,F2,F3,F4,F5,F6,F7). Lists (from Clocksin) Lists are the same as in other languages (such as ML) in that a list of terms of any length is composed of list cells that are ‘consed’ together. The list of length 0 is called nil, written []. The list of length n is .(head,tail), where tail is a list of length n-1. So a list cell is a functor ‘.’ of arity 2. Its first component is the head, and the second component is the tail. Lists - examples (from Clocksin) nil .(a, nil) .(a, .(b, nil) .(a, .(b, .(c, .(d, .(e. nil))))) .(a,b) (note this is a pair, not a proper list) .(a, X) (this might be a list, or might not!) .(a, .(b, nil)), .(c, nil)) Lists can be written as trees a a nil b nil a b a a b c a d e nil a b nil nil X Lists - PROLOG syntax Nil is written []. The list consisting of n elements t1, t2, …,tn is written [t1, t2, …,tn]. .(X,Y) is written [X|Y] [X|[]] is written [X] The term .(a, .(b, .(c,Y))) is written [a,b,c|Y]. If Y is instantiated to [], then the term is a list, and can be written [a,b,c|[]] or simply [a,b,c]. Lists - Exercise 1 Identify the heads and tails of these lists (if any): [a, b, c] [a] [] [[the, cat], sat] [[the, cardinal], [pulled, [off]], [each, [plum, coloured], shoe] Lists - Exercise 1 Identify the heads and tails of these lists (if any): a [b, c] [a] [] [[the, cat], sat] [[the, cardinal], [pulled, [off]], [each, [plum, coloured], shoe] Lists - Exercise 1 Identify the heads and tails of these lists (if any): [a, b, c] a [] [] [[the, cat], sat] [[the, cardinal], [pulled, [off]], [each, [plum, coloured], shoe] Lists - Exercise 1 Identify the heads and tails of these lists (if any): [a, b, c] [a] [] (not a list, so doesn’t have head and tail. nil is a constant) [[the, cat], sat] [[the, cardinal], [pulled, [off]], [each, [plum, coloured], shoe] Lists - Exercise 1 Identify the heads and tails of these lists (if any): [a, b, c] [a] [] [the, cat] [sat] [[the, cardinal], [pulled, [off]], [each, [plum, coloured], shoe] Lists - Exercise 1 Identify the heads and tails of these lists (if any): [a, b, c] [a] [] [[the, cat], sat] [the, cardinal] coloured], shoe] [pulled, [off]], [each, [plum, Lists - Exercise 2 For each pair of terms, determine whether they unify, and if so, to which terms are the variables instantiated? [X, Y, Z] [john, likes, fish] [cat] [X|Y] [X,Y|Z] [mary, likes, wine] [[the,Y]|Z] [[X,answer], [is, here]] [X, Y, X] [a, Z, Z] [[X], [Y], [X]] [[a], [X], [X]] Lists - Exercise 2 A variable may be instantiated to any term. X Y Z mary likes wine [mary, likes, wine] [] [X,Y|Z] “member” predicate member(X, [X|T]). member(X, [H|T]) :- member(X, T). Examples: ?- member(john, [paul, john]). ?- member(X, [paul, john]). ?- member(joe, [marx, darwin, freud]). ?- member(foo, X). “member” predicate member(X, [X|T]). Notice T isn’t ‘used’ member(X, [H|T]) :- member(X, T). member(X, [X|_]). member(X, [_|T]) :- member(X, T). Notice H isn’t ‘used’ Exercise 3 Here is a mystery predicate. What does it do? mystery(X, A, B) :- member(X, A), member(X, B). ?- mystery(a, [b, c, a], [p, a, l]). ?- mystery(b, [b, l, u, e], [y, e, l, l, o, w]). ?- mystery(X, [r, a, p, i, d], [a, c, t, i, o, n]). ?- mystery(X, [w, a, l, n, u, t], [c, h, e, r, r, y]). Length of a list - Exercise 4 Naïve method: length([], 0). length([H|T], N) :- length(T, NT), N is NT + 1. Length of a list - Tail recursion Procedures such as length/2: length([], 0). length([H|T], N) :- length(T, NT), N is NT + 1. often crash when processing large lists, even with a few thousand elements. This happens because in the recursive rule, the recursive call is not the last goal on the rhs and so may need to be backtracked into. For each call, Prolog must store the choice points in a memory stack of fixed size. Length of a list - Tail recursion No matter how large this memory stack is, it will overflow if the list is long enough. This is less likely to happen if the recursive call is the last goal on the rhs - because within each call there is no choice point for it. Procedures in which recursive calls appear as the last goal in the rule(s) are known as tail recursive. There is a way of re-writing procedures such as length/2 to make them tail recursive. Length of a list - Tail recursion The accumulator algorithm for the length of a list is: Initialise the current sub-total, LengthSoFar, to 0. To find the length of L while L is non-empty do for each element of L remove the element and add 1 to LengthSoFar when L is empty set Length = LengthSoFar. Length of a list - Exercise 4 Tail-recursive method: length(L, N) :- acc(L, 0, N). /* acc(List, LengthSoFar, Length) */ acc([], A, A). acc([H|T], A, N) :- A1 is A + 1, acc(T, A1, N). Length of a list - Exercise 4 ?- length([apple, pear], N). ?- length([alpha], 2). ?- length(L, 3). Modify length to give a procedure sum such that sum(L,N) succeeds if L is a list of integers and N is their sum. “concat” predicate - Exercise 5 Write a predicate for concatenating 2 lists, i.e. ?-concat([a,b,c,d],[1,2,3],Result). Result = [a,b,c,d,1,2,3] ? Yes “reverse” predicate - Exercise 6 Write a predicate for reversing a list, i.e. ?-reverse([a,b,c,d],Result). Result = [d,c,b,a] ? Yes “sublist” predicate - Exercise 7 Write a predicate that checks whether a given list is a sublist (in the same order) of another, i.e. ?-sublist([a,b,c,d],[a,c]). Yes ?-sublist([a,b,c,d],[c,a]). No “setify” predicate - Exercise 8 Write a predicate that removes duplicate elements from a given list, i.e. ?-setify([a,b,a,a,c,b,a,d],Result). Result = [a,b,c,d] ? Yes “split” predicate - Exercise 9 Write a predicate that splits a given list of numbers into lists of odd and even numbers, i.e. ?-split([1,2,3,4,5,5,6,8,7,9,2,3],R1,R2). R1 = [1,3,5,5,7,9,3], R2 = [2,4,6,8,2] ? Yes