Prolog for LinguistsSymbolic Systems 139P/239P
John Dowding
Week 2, October 15, 2001
Administrivia
Registration: Symbolic Systems or Linguistics
Bookstore will start returning C&M books at Oct. 22nd.
Course web page
http://www.stanford.edu/class/symbsys139p
programs used in class power point slides homework assignments, solutions
Office Hours
We have reserved 4 workstations in the Unix Cluster in Meyer library, fables 1-4
4:30-5:30 on Thursday
Course Schedule
1. Oct. 82. Oct. 153. Oct. 224. Oct. 29 (double up)5. Nov. 56. Nov. 127. Nov. 26 (double up)8. Dec. 3
No class on Nov. 19
Prolog program
A Prolog program is defined by a set of Predicates
Each Predicate has a unique Functor and Arityparent(Parent, Child)
a predicate whose functor is “parent” with arity 2.
Each Predicate is defined by a sequence of Clauses
A Clause is either a Fact or a Rule
fact(…).
head(…) :- goal1(…), … , goalN(…).
Each argument to a predicate is a Term
Terms
Each argument to a predicate is a Term
A Term is either: Atomic Variable Compound
Atoms are either constant symbols, or numbers
Compound terms have a functor and arity: functor(Arg1, Arg2, …, ArgN) Each Arg is itself a Term.
Homework solutions
exponential(+Base, +Exponent, ?Result) Base case: Base^0 = 1 Recursive case: Base ^ (N+1) = Base * (Base^N)
% exponential(+Base, +Exponent, ?Result)
exponential(Base, 0, s(0)):-
is_number(Base).
exponential(Base, s(Exponent), Result):-
exponential(Base, Exponent, PartialResult),
mult(PartialResult, Base, Result).
Factorial
factorial(+N, ?Factorial) fact(1) = 1 fact(N+1)= (N+1) * fact(N)
%factorial(+Number, ?Factorial)
factorial(s(0), s(0)).
factorial(s(Number), Factorial):-
factorial(Number, PartialFactorial),
mult(s(Number), PartialFactorial, Factorial).
Prolog Execution Model/Prolog Debugger
CALL EXIT
FAIL REDOparent(james, john).parent(james, alan).parent(florence, john).parent(florence, alan).parent(alan, elizabeth).parent(alan, emily).
Goal = parent(P, john) parent(james, john)parent(florence, john)
Execution Model (conjunctions)
parent(james, john).parent(james, alan).parent(florence, john).parent(florence, alan).parent(alan, elizabeth).parent(alan, emily).
female(emily).female(florence).female(elizabeth).
parent(Mother, john) female(Mother)parent(james, john) female(james)parent(florence, john) female(florence)
Execution Model – mult(s(s(s(0))), s(s(0)), Result)
mult(0, Term, 0):- is_number(Term).mult(s(Term1), Term2, Product):- mult(Term1, Term2, Partial), add(Term2, Partial, Product).
add(0, Sum, Sum):- is_number(Sum).add(s(Addend1), Addend2, s(Sum)):- add(Addend1, Addend2, Sum).
mult(s(s(0)),s(s(0)), Prod)
mult(s(0), s(s(0)), Partial) add(s(s(0)), Partial, Prod)
add(s(s(0)), Prod, Result)
mult(0, Term, 0):- is_number(Term).mult(s(Term1), Term2, Product):- mult(Term1, Term2, Partial), add(Term2, Partial, Product).
Prolog Debugger Demo
Built-In predicates: trace/0. notrace/0.
Debugger actions: ‘c’ or <cr> - creep ‘s’ – skip ‘l’ – leap ‘r’ – retry ‘f’ – fail ‘a’ - abort
And-Or Trees
or
andand and
ororor
ororor or
andandandandand and and
orororor
oror
or
And-Or Tree (cont.)
or
and and
mult(0, Term, 0):- is_number(Term).
mult(s(Term1), Term2, Product):- mult(Term1, Term2, Partial), add(Term2, Partial, Product).
or or or
is_number(Term)mult(Term1, Term2, Partial)
add(Term2,Partial,Product)
and and and and and and
Linked Lists
Prolog allows a special syntax for lists: [a,b,c] is a list of 3 elements [] is a special atom indicating a list with 0 elements
Internally, Prolog lists are regular Prolog terms with the functor ‘.’ (so called “dotted pairs”)[a,b,c] = ‘.’(a, ‘.’(b, ‘.’(c, []))).The symbol | in a list indicates “rest of list”, or the term that is the 2nd argument of a dotted pair.[a,b,c] = [a|[bc]].[Head|Tail] is a common expression for dividing a list into its first element (Head) and the rest of the list (Tail).
Example: list/1
% list(?List)
list([]).
list([_Head|Tail]):-
list(Tail).
Since Prolog is untyped, we don’t have to know anything about Head except that it is a term.
Example: member/2
% member(?Element, ?List)
member(Element, [Element|_Tail]).
member(Element, [_Head|Tail]):-
member(Element, Tail).
Example: delete/3
% delete(+Element, +List, -NewList)
% delete/3 succeeds if NewList results from removing
% one occurrence of Element from List.
delete(Element, [Element|Tail], Tail).
delete(Element, [Head|Tail], [Head|NewTail]):-
delete(Element, Tail, NewTail).
Example: append/3
% append(?List1, ?List2, ?List3)
% append/3 succeds if List3 contains all the elements of
% List1, followed by all the elements of List2.
append([], List2, List2).
append([Head|List1], List2, [Head|List3]):-
append(List1, List2, List3).
Example: sublist/3
% sublist(?SubList, +List)
sublist(SubList, List):-
append(_List1, List2, List),
append(SubList, _List3, List2).
1st append finds a beginning point for the sublist
2nd append finds an end point
Example: sublist/3 (cont)
sublist1(SubList, List):-
append(List1, _List2, List),
append(_List3, SubList, List1).
Example: “naïve” reverse
% "naive reverse": nreverse(?List, ?ReversedList).
nreverse([], []).
nreverse([Head|Tail], ReversedList):-
nreverse(Tail, ReversedTail),
append(ReversedTail, [Head], ReversedList).
Example: efficient reverse/3
% reverse(+List, -ReversedList)
reverse(List, ReversedList):-
reverse_helper(List, [], ReversedList).
reverse_helper([], ReversedList, ReversedList).
reverse_helper([Head|Tail], PartialList, ReversedList):-
reverse_helper(Tail, [Head|PartialList], ReversedList).
“Pure Prolog” and non-logical built-ins
All the examples so far have been “pure Prolog” Contain no built-ins with non-logical side-effects
Prolog has many built-in predicates that have such side-effects: Type checking of terms Arithmetic Control execution Input and output Modify the program during execution Perform aggregation operations
Use of non-logical built-in predicates usually effects the reversability of your program.
Type-checking Built-in Predicates
var(X) – is true when X is an uninstantiated variable.
nonvar(X) – is true when X is not a variable.
atom(X) – is true when X is a symbolic constant.
number(X) – is true when X is a number
atomic(X) – is true when atom(X) or number(X).
compound(X) – is true when X is a compound term.
Term constructor/selectors: functor/3, arg/3
functor(+Term, ?Functor, ?Arity) Find the Functor and Arity of Term
functor(?Term, +Functor, +Arity) Constructs a new Term with Functor and Arity
arg(+N, +Term, ?SubTerm) Unifies SubTerm with the Nth argument of Term
Arithmetic: Built-In is/2
Arithmetic expressions are not normally evaluated in Prolog.Built-In infix operator is/2 evaluates it’s 2nd argument, and unifies the result with it’s 1st argument.| ?- X = 5 + 2.X = 5+2?yes| ?- X is 5 + 2.X = 7 ?yes
Any variables in the right-hand side of is/2 must be instantiated when it is evaluated.
Revisit operator and arithmetic at a later time
Cut (!)
The ! Symbol (pronounced “cut”) modifies the execution of your program by committing to certain choices. That is, it removes choice points.
Easy to describe what it does, more difficult to get used to using it properly.
Cut (cont.)
Head1 :- Goal1, Goal2, …, GoalN, !, …Head2 :- …Head3 :- ……HeadN :- …
Removes the choice point that allows Head2 …HeadNRemoves any choice points that may have been introduced in Goal1 … GoalN.We will discuss Cut in more detail later on.
Example: delete_first/3
% delete_first(+Element, +List, -NewList)
% removes the 1st occurrence of Element in List.
delete(Element, [Element|Tail], Tail):-
!.
delete(Element, [Head|Tail], [Head|NewTail]):-
delete(Element, Tail, NewTail).
Example: is_term/1
is_term(Atomic) :- atomic(Atomic).is_term(Variable):- var(Variable).is_term(CompoundTerm):-
compound(CompoundTerm), functor(CompoundTerm, _Functor, Arity).
is_term_helper(Arity, CompoundTerm).
is_term_helper(0, _CompoundTerm) :- !is_term_helper(Index, CompoundTerm):-
arg(Index, CompoundTerm, SubTerm),is_term(SubTerm),NextIndex is Index – 1,is_term_helper(NextIndex, CompoundTerm).
Homework
Read section in Sicstus Prolog manual on debugger.
Use debugger to trace through today’s example programs and understand how the work.
Implement: delete_all(+Element, +List, -NewList) that removes all
occurrences of Element from List to find NewList. replace_all(+Element, +List, +NewElement, -NewList) replaces
every occurrence of Element with NewElement in List to give NewList.