Prolog: List http://www.learnprolognow.org © Patrick Blackburn, Johan Bos & Kristina Striegnitz.

Slides:



Advertisements
Similar presentations
© Johan Bos Logic Programming About the course –Taught in English –Tuesday: mostly theory –Thursday: practical work [lab] Teaching material –Learn Prolog.
Advertisements

Formal Models of Computation Part II The Logic Model
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 10: Cuts and Negation Theory –Explain how to control Prolog`s backtracking behaviour with.
3. Lists, Operators, Arithmetic. Contents Representation of lists Some operations on lists Operator notation Arithmetic.
Chapter 3: Lists, Operators, Arithmetic Part 1. Outline Representation of lists Some operations in lists Operator notation Arithmetic.
Lisp. Versions of LISP Lisp is an old language with many variants Lisp is alive and well today Most modern versions are based on Common Lisp LispWorks.
Computer Science CPSC 322 Lecture 25 Top Down Proof Procedure (Ch 5.2.2)
Lecturer: Dr. Abeer Mahmoud Logic Programming in Prolog.
C. Varela; Adapted w/permission from S. Haridi and P. Van Roy1 Declarative Programming Techniques Accumulators, Difference Lists (VRH ) Carlos Varela.
Prolog.
Declarative Programming Lists in PROLOG Autumn 2014.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 6: More Lists Theory –Define append/3, a predicate for concatenating two lists, and illustrate.
LING 388: Language and Computers Sandiway Fong Lecture 5: 9/5.
Prolog Programming (Volume 5) Dr W.F. Clocksin. List cells + Unification = Great Idea Normally we use ‘proper lists’, which are defined according to the.
Introduction to PROLOG ME 409 Lab - 1. Introduction to PROLOG.
Chapter Three: Lists, Operators, Arithmetic CS 461.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 6: More Lists Theory –Define append/3, a predicate for concatenating two lists, and illustrate.
11/10/04 AIPP Lecture 6: Built-in Predicates1 Combining Lists & Built-in Predicates Artificial Intelligence Programming in Prolog Lecturer: Tim Smith Lecture.
Lists in Lisp and Scheme a. Lists are Lisp’s fundamental data structures, but there are others – Arrays, characters, strings, etc. – Common Lisp has moved.
Chapter Three: Lists, Operators, Arithmetic 1. Chapter three: 3.1Representation of lists 3.2Some operations on lists 2.
1 Introduction to Prolog References: – – Bratko, I., Prolog Programming.
Automated Reasoning Systems For first order Predicate Logic.
1 Logic Programming. 2 A little bit of Prolog Objects and relations between objects Facts and rules. Upper case are variables. parent(pam, bob).parent(tom,bob).
Chapter 11 Proof by Induction. Induction and Recursion Two sides of the same coin.  Induction usually starts with small things, and then generalizes.
Functional Programming. Pure Functional Programming Computation is largely performed by applying functions to values. The value of an expression depends.
Recursion. Recursion is a powerful technique for thinking about a process It can be used to simulate a loop, or for many other kinds of applications In.
For Friday Read “lectures” 1-5 of Learn Prolog Now: prolog-now/
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 10 Exercises –Solutions to Exercises of LPN chapter 9 Theory –Explain how to control Prolog`s.
Lisp. Versions of LISP Lisp is an old language with many variants –LISP is an acronym for List Processing language Lisp is alive and well today Most modern.
16-Jun-15 Recursion. 2 Definitions I A recursive definition is a definition in which the thing being defined occurs as part of its own definition Example:
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Logic Programming About the course –Taught in English –Tuesday: mostly theory –Thursday: practical.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 5: Arithmetic Theory –Introduce Prolog`s built-in abilities for performing arithmetic –Apply.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 7: Definite Clause Grammars Theory –Introduce context free grammars and some related concepts.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 4: Lists Theory –Introduce lists, an important recursive data structure often used in Prolog.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 2 Theory –Unification –Unification in Prolog –Proof search Exercises –Correction exercises.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 9: A closer look at terms Theory –Introduce the == predicate –Take a closer look at term structure.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 5: Arithmetic Theory –Introduce Prolog`s built-in abilities for performing arithmetic –Apply.
28-Jun-15 Recursion. 2 Definitions I A recursive definition is a definition in which the thing being defined occurs as part of its own definition Example:
Recursion. Definitions I A recursive definition is a definition in which the thing being defined occurs as part of its own definition Example: A list.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 4: Lists Theory –Introduce lists, an important recursive data structure often used in Prolog.
1 MA 1128: Lecture 09 – 6/08/15 Solving Systems of Linear Equations.
Induction and recursion
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Horn clauses A literal is an atomic formula or its negation A clause is a disjunction of literals.
CS 321 Programming Languages and Compilers Prolog part 2.
Agile Software Development Lab Dr. Günter Kniesel, Daniel Speicher, Tobias Rho Spring 2008 Prolog - Part 2 Patrick Rypalla Alexis Raptarchis
Linked Structures See Section 3.2 of the text.. First, notice that Java allows classes to be recursive, in the sense that a class can have an element.
30/09/04 AIPP Lecture 3: Recursion, Structures, and Lists1 Recursion, Structures, and Lists Artificial Intelligence Programming in Prolog Lecturer: Tim.
MB: 5 March 2001CS360 Lecture 41 Programming in Logic: Prolog Lists and List Operations Readings: Sections 3.1 & 3.2.
Chapter Three: Lists, Operators, Arithmetic 1. © Patrick Blackburn, Johan Bos & Kristina Striegnitz Important things about lists  List elements are enclosed.
1 Prolog and Logic Languages Aaron Bloomfield CS 415 Fall 2005.
© Patrick Blackburn, Johan Bos & Kristina Striegnitz Lecture 9: A closer look at terms Theory –Introduce the == predicate –Take a closer look at term structure.
Lists in Prolog Sections 3.1, 3.2. Lists n List = sequence of values –[1, 2, 3, 4, 5] –[bob, brian, cathy, mark, david, loretta] –[birds(4, calling),
Chapter 5 Linked List by Before you learn Linked List 3 rd level of Data Structures Intermediate Level of Understanding for C++ Please.
For Monday Exam 1 is Monday Takehome due Prolog Handout 3 due.
CS 554: Knowledge base systems Part-4: Prolog- 2 By Dr. Syed Noman Hasany.
For Friday No reading Prolog Handout 2. Homework.
07/10/04 AIPP Lecture 5: List Processing1 List Processing Artificial Intelligence Programming in Prolog Lecturer: Tim Smith Lecture 5 07/10/04.
C H A P T E R N I N E Logic Programming Part 2 Programming Languages – Principles and Paradigms by Allen Tucker, Robert Noonan.
Recursion ITI 1121 N. El Kadri. Reminders about recursion In your 1 st CS course (or its equivalent), you have seen how to use recursion to solve numerical.
INF3110 Group 2 EXAM 2013 SOLUTIONS AND HINTS. But first, an example of compile-time and run-time type checking Imagine we have the following code. What.
Recursion. Definitions I A recursive definition is a definition in which the thing being defined occurs as part of its own definition Example: A list.
CMSC201 Computer Science I for Majors Lecture 19 – Recursion
CMSC201 Computer Science I for Majors Lecture 18 – Recursion
Lists in Lisp and Scheme
Lists Prolog Pepper Credit to : Blackburn, Patrick, Johan Bos and Kristina Striegnitz. Learn Prolog Now. London: College Publications, (ISBN )
Programming Paradigms and Languages
Programming Techniques
Lecture 7: Definite Clause Grammars
Lisp.
Introduction to Computer Science
Presentation transcript:

Prolog: List http://www.learnprolognow.org © Patrick Blackburn, Johan Bos & Kristina Striegnitz

Lists A list is a finite sequence of elements Examples of lists in Prolog: [mia, vincent, jules, yolanda] [mia, robber(honeybunny), X, 2, mia] [ ] [mia, [vincent, jules], [butch, friend(butch)]] [[ ], dead(z), [2, [b,c]], [ ], Z, [2, [b,c]]]

Important things about lists List elements are enclosed in square brackets The length of a list is the number of elements it has All sorts of Prolog terms can be elements of a list There is a special list: the empty list [ ]

Head and Tail A non-empty list can be thought of as consisting of two parts The head The tail The head is the first item in the list The tail is everything else The tail is the list that remains when we take the first element away The tail of a list is always a list

Head and Tail example 1 [mia, vincent, jules, yolanda] Head: Tail:

Head and Tail example 1 [mia, vincent, jules, yolanda] Head: mia Tail:

Head and Tail example 1 [mia, vincent, jules, yolanda] Head: mia Tail: [vincent, jules, yolanda]

Head and Tail example 2 [[ ], dead(z), [2, [b,c]], [ ], Z, [2, [b,c]]] Head: Tail:

Head and Tail example 2 [[ ], dead(z), [2, [b,c]], [ ], Z, [2, [b,c]]] Head: [ ] Tail:

Head and Tail example 2 [[ ], dead(z), [2, [b,c]], [ ], Z, [2, [b,c]]] Head: [ ] Tail: [dead(z), [2, [b,c]], [ ], Z, [2, [b,c]]]

Head and Tail example 3 [dead(z)] Head: Tail:

Head and Tail example 3 [dead(z)] Head: dead(z) Tail:

Head and Tail example 3 [dead(z)] Head: dead(z) Tail: [ ]

Head and tail of empty list The empty list has neither a head nor a tail For Prolog, [ ] is a special simple list without any internal structure The empty list plays an important role in recursive predicates for list processing in Prolog

The built-in operator | Prolog has a special built-in operator | which can be used to decompose a list into its head and tail The | operator is a key tool for writing Prolog list manipulation predicates

The built-in operator | ?- [Head|Tail] = [mia, vincent, jules, yolanda]. Head = mia Tail = [vincent,jules,yolanda] yes ?-

The built-in operator | ?- [X|Y] = [mia, vincent, jules, yolanda]. X = mia Y = [vincent,jules,yolanda] yes ?-

The built-in operator | ?- [X|Y] = [ ]. no ?-

The built-in operator | ?- [X,Y|Tail] = [[ ], dead(z), [2, [b,c]], [], Z, [2, [b,c]]] . X = [ ] Y = dead(z) Z = _4543 Tail = [[2, [b,c]], [ ], Z, [2, [b,c]]] yes ?-

Anonymous variable Suppose we are interested in the second and fourth element of a list ?- [X1,X2,X3,X4|Tail] = [mia, vincent, marsellus, jody, yolanda]. X1 = mia X2 = vincent X3 = marsellus X4 = jody Tail = [yolanda] yes ?-

Anonymous variables There is a simpler way of obtaining only the information we want: ?- [ _,X2, _,X4|_ ] = [mia, vincent, marsellus, jody, yolanda]. X2 = vincent X4 = jody yes ?- The underscore is the anonymous variable

Member One of the most basic things we would like to know is whether something is an element of a list or not So let`s write a predicate that when given a term X and a list L, tells us whether or not X belongs to L This predicate is usually called member/2

member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?-

member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(yolanda,[yolanda,trudy,vincent,jules]).

member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(yolanda,[yolanda,trudy,vincent,jules]). yes ?-

member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(vincent,[yolanda,trudy,vincent,jules]).

member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(vincent,[yolanda,trudy,vincent,jules]). yes ?-

member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(zed,[yolanda,trudy,vincent,jules]).

member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(zed,[yolanda,trudy,vincent,jules]). no ?-

member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(X,[yolanda,trudy,vincent,jules]).

member/2 member(X,[X|T]). member(X,[H|T]):- member(X,T). ?- member(X,[yolanda,trudy,vincent,jules]). X = yolanda; X = trudy; X = vincent; X = jules; no

Rewriting member/2 member(X,[X|_]). member(X,[_|T]):- member(X,T).

Recursing down lists The member/2 predicate works by recursively working its way down a list doing something to the head, and then recursively doing the same thing to the tail This technique is very common in Prolog and therefore very important that you master it So let`s look at another example!

Example: a2b/2 The predicate a2b/2 takes two lists as arguments and succeeds if the first argument is a list of as, and the second argument is a list of bs of exactly the same length ?- a2b([a,a,a,a],[b,b,b,b]). yes ?- a2b([a,a,a,a],[b,b,b]). no ?- a2b([a,c,a,a],[b,b,b,t]).

Defining a2b/2: step 1 a2b([],[]). Often the best away to solve such problems is to think about the simplest possible case Here it means: the empty list

Defining a2b/2: step 2 Now think recursively! a2b([a|L1],[b|L2]):- a2b(L1,L2). Now think recursively! When should a2b/2 decide that two non-empty lists are a list of as and a list of bs of exactly the same length?

Testing a2b/2 ?- a2b([a,a,a],[b,b,b]). yes ?- a2b([],[]). a2b([a|L1],[b|L2]):- a2b(L1,L2). ?- a2b([a,a,a],[b,b,b]). yes ?-

Testing a2b/2 ?- a2b([a,a,a,a],[b,b,b]). no ?- a2b([],[]). a2b([a|L1],[b|L2]):- a2b(L1,L2). ?- a2b([a,a,a,a],[b,b,b]). no ?-

Testing a2b/2 ?- a2b([a,t,a,a],[b,b,b,c]). no ?- a2b([],[]). a2b([a|L1],[b|L2]):- a2b(L1,L2). ?- a2b([a,t,a,a],[b,b,b,c]). no ?-

Further investigating a2b/2 a2b([a|L1],[b|L2]):- a2b(L1,L2). ?- a2b([a,a,a,a,a], X). X = [b,b,b,b,b] yes ?-

Further investigating a2b/2 a2b([a|L1],[b|L2]):- a2b(L1,L2). ?- a2b(X,[b,b,b,b,b,b,b]). X = [a,a,a,a,a,a,a] yes ?-

Append We will define an important predicate append/3 whose arguments are all lists Declaratively, append(L1,L2,L3) is true if list L3 is the result of concatenating the lists L1 and L2 together ?- append([a,b,c,d],[3,4,5],[a,b,c,d,3,4,5]). yes ?- append([a,b,c],[3,4,5],[a,b,c,d,3,4,5]). no

Append viewed procedurally From a procedural perspective, the most obvious use of append/3 is to concatenate two lists together We can do this simply by using a variable as third argument ?- append([a,b,c,d],[1,2,3,4,5], X). X=[a,b,c,d,1,2,3,4,5] yes ?-

Definition of append/3 append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3). Recursive definition Base clause: appending the empty list to any list produces that same list The recursive step says that when concatenating a non-empty list [H|T] with a list L, the result is a list with head H and the result of concatenating T and L

How append/3 works Two ways to find out: Use trace/0 on some examples Draw a search tree! Let us consider a simple example ?- append([a,b,c],[1,2,3], R).

Search tree example ?- append([a,b,c],[1,2,3], R). append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

Search tree example ?- append([a,b,c],[1,2,3], R). / \ / \ append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

Search tree example ?- append([a,b,c],[1,2,3], R). / \ / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

Search tree example ?- append([a,b,c],[1,2,3], R). / \ / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

Search tree example ?- append([a,b,c],[1,2,3], R). / \ / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

Search tree example ?- append([a,b,c],[1,2,3], R). / \ / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) / \ append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

Search tree example ?- append([a,b,c],[1,2,3], R). / \ / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) / \ † L1=[c|L2] ?- append([],[1,2,3],L2) append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

Search tree example ?- append([a,b,c],[1,2,3], R). / \ / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) / \ † L1=[c|L2] ?- append([],[1,2,3],L2) / \ append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

Search tree example ?- append([a,b,c],[1,2,3], R). / \ / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) / \ † L1=[c|L2] ?- append([],[1,2,3],L2) / \ L2=[1,2,3] † append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

Search tree example ?- append([a,b,c],[1,2,3], R). / \ / \ † R = [a|L0] ?- append([b,c],[1,2,3],L0) / \ † L0=[b|L1] ?- append([c],[1,2,3],L1) / \ † L1=[c|L2] ?- append([],[1,2,3],L2) / \ L2=[1,2,3] † append([], L, L). append([H|L1], L2, [H|L3]):- append(L1, L2, L3). L2=[1,2,3] L1=[c|L2]=[c,1,2,3] L0=[b|L1]=[b,c,1,2,3] R=[a|L0]=[a,b,c,1,2,3]

Using append/3 Now that we understand how append/3 works, let`s look at some applications Splitting up a list: ?- append(X,Y, [a,b,c,d]). X=[ ] Y=[a,b,c,d]; X=[a] Y=[b,c,d]; X=[a,b] Y=[c,d]; X=[a,b,c] Y=[d]; X=[a,b,c,d] Y=[ ]; no

Prefix and suffix We can also use append/3 to define other useful predicates A nice example is finding prefixes and suffixes of a list

Definition of prefix/2 prefix(P,L):- append(P,_,L). A list P is a prefix of some list L when there is some list such that L is the result of concatenating P with that list. We use the anonymous variable because we don`t care what that list is.

Use of prefix/2 ?- prefix(X, [a,b,c,d]). X=[ ]; X=[a]; X=[a,b]; prefix(P,L):- append(P,_,L). ?- prefix(X, [a,b,c,d]). X=[ ]; X=[a]; X=[a,b]; X=[a,b,c]; X=[a,b,c,d]; no

Definition of suffix/2 suffix(S,L):- append(_,S,L). A list S is a suffix of some list L when there is some list such that L is the result of concatenating that list with S. Once again, we use the anonymous variable because we don`t care what that list is.

Use of suffix/2 ?- suffix(X, [a,b,c,d]). X=[a,b,c,d]; X=[b,c,d]; suffix(S,L):- append(_,S,L). ?- suffix(X, [a,b,c,d]). X=[a,b,c,d]; X=[b,c,d]; X=[c,d]; X=[d]; X=[]; no

append/3 and efficiency The append/3 predicate is useful, and it is important to know how to to use it It is of equal importance to know that append/3 can be source of inefficiency Why? Concatenating a list is not done in a simple action But by traversing down one of the lists

Question Using append/3 we would like to concatenate two lists: List 1: [a,b,c,d,e,f,g,h,i] List 2: [j,k,l] The result should be a list with all the elements of list 1 and 2, the order of the elements is not important Which of the following goals is the most efficient way to concatenate the lists? ?- append([a,b,c,d,e,f,g,h,i],[j,k,l],R). ?- append([j,k,l],[a,b,c,d,e,f,g,h,i],R).

Answer Look at the way append/3 is defined It recurses on the first argument, not really touching the second argument That means it is best to call it with the shortest list as first argument Of course you don’t always know what the shortest list is, and you can only do this when you don’t care about the order of the elements in the concatenated list But if you do it can help make your Prolog code more efficient

Reversing a List We will illustrate the problem with append/3 by using it to reverse the elements of a list That is we will define a predicate that changes a list [a,b,c,d,e] into a list [e,d,c,b,a] This would be a useful tool to have, as Prolog only allows easy access to the front of the list

Naïve reverse Recursive definition If we reverse the empty list, we obtain the empty list If we reverse the list [H|T], we end up with the list obtained by reversing T and concatenating it with [H] To see that this definition is correct, consider the list [a,b,c,d]. If we reverse the tail of this list we get [d,c,b]. Concatenating this with [a] yields [d,c,b,a]

Naïve reverse in Prolog naiveReverse([],[]). naiveReverse([H|T],R):- naiveReverse(T,RT), append(RT,[H],R). This definition is correct, but it does an awful lot of work It spends a lot of time carrying out appends But there is a better way…

Reverse using an accumulator The better way is using an accumulator The accumulator will be a list, and when we start reversing it will be empty We simply take the head of the list that we want to reverse and add it to the the head of the accumulator list We continue this until we hit the empty list At this point the accumulator will contain the reversed list!

Reverse using an accumulator accReverse([ ],L,L). accReverse([H|T],Acc,Rev):- accReverse(T,[H|Acc],Rev).

Adding a wrapper predicate accReverse([ ],L,L). accReverse([H|T],Acc,Rev):- accReverse(T,[H|Acc],Rev). reverse(L1,L2):- accReverse(L1,[ ],L2).

Illustration of the accumulator List: [a,b,c,d] Accumulator: []

Illustration of the accumulator List: [a,b,c,d] List: [b,c,d] Accumulator: [] Accumulator: [a]

Illustration of the accumulator List: [a,b,c,d] List: [b,c,d] List: [c,d] Accumulator: [] Accumulator: [a] Accumulator: [b,a]

Illustration of the accumulator List: [a,b,c,d] List: [b,c,d] List: [c,d] List: [d] Accumulator: [] Accumulator: [a] Accumulator: [b,a] Accumulator: [c,b,a]

Illustration of the accumulator List: [a,b,c,d] List: [b,c,d] List: [c,d] List: [d] List: [] Accumulator: [] Accumulator: [a] Accumulator: [b,a] Accumulator: [c,b,a] Accumulator: [d,c,b,a]

Summary of this lecture In this lecture we introduced list and recursive predicates that work on lists The kind of programming that these predicates illustrated is fundamental to Prolog