400 likes | 491 Views
Declarative Programming. Autumn 2014. Lists in PROLOG. Example - Fibonacci numbers. Fibonacci numbers are defined as follows: 0, if i = 0 F(i) = 1, if i = 1 F(i – 1) + F(i – 2), if i > 1. Example - Fibonacci numbers. Fibonacci numbers are defined as follows:
E N D
Declarative Programming Autumn 2014 Lists in PROLOG
Example - Fibonacci numbers Fibonacci numbers are defined as follows: 0, if i = 0 F(i) = 1, if i = 1 F(i–1) + F(i – 2), if i > 1
Example - Fibonacci numbers Fibonacci numbers are defined as follows: 0, if i = 0 F(i) = 1, if i = 1 F(i–1) + F(i – 2), 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: 0, if i = 0 S(i) = 1, if i = 1 i*S(0)+ (i–1)*S(1)+...+2S(i–1), if i > 1
Example - Fibonacci numbers What, if we want something like this: 0, if i = 0 S(i) = 1, if i = 1 i*S(0)+ (i–1)*S(1)+...+2S(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 represents the empty list list(a,nil) represents list a list(a,list(b,nil)) represents list a,b list(a,list(b,list(c,nil))) 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)))) :- X1 is X–1, fibonacci(X1,list(R1,list(R2,Z))), R is R1+R2.
Lists - predefined notation [] represents the empty list .(a,[]) represents list a .(a,.(b,[])) represents list a,b .(a,.(b,.(c,[]))) 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 X a b c a a nil d b nil e nil
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] [pulled, [off]], [each, [plum, coloured], shoe]
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]). member(X, [H|T]) :- member(X, T). member(X, [X|_]). member(X, [_|T]) :- member(X, T). Notice T isn’t ‘used’ 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