440 likes | 547 Views
Prolog for Linguists Symbolic Systems 139P/239P. John Dowding Week 3, October 22, 2001 jdowding@stanford.edu. Course web page. http://www.stanford.edu/class/symbsys139p programs used in class power point slides homework assignments, solutions
E N D
Prolog for Linguists Symbolic Systems 139P/239P John Dowding Week 3, October 22, 2001 jdowding@stanford.edu
Course web page • http://www.stanford.edu/class/symbsys139p • programs used in class • power point slides • homework assignments, solutions • This gets updated by Tuesday night after Monday’s class.
Office Hours • We have reserved 4 workstations in the Unix Cluster in Meyer library, fables 1-4 • Skipping 4:30-5:30 on Thursday this week • Friday 3:30-4:30, after NLP Reading Group this week • If not, contact me and we can make other arrangements
Course Schedule • Oct. 8 • Oct. 15 • Oct. 22 • Oct. 29 (double up) • Nov. 5 • Nov. 12 • Nov. 26 (double up) • Dec. 3 No class on Nov. 19
Prolog Execution Model/Prolog Debugger EXIT CALL FAIL REDO
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).
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.
Homework: delete_all/3 %delete_all(+Element, +List, -NewList) delete_all(_Element, [], []). delete_all(Element, [Element|List], NewList) :- !, delete_all(Element, List, NewList). delete_all(Element, [Head|List], [Head|NewList]) :- delete_all(Element, List, NewList).
Homework: replace_all/4 %replace_all(+Element, +List, +NewElement, -NewList) replace_all(_Element, [], _NewElement, []). replace_all(Element, [Element|List], NewElement, [NewElement|NewList]) :- !, replace_all(Element, List, NewElement, NewList). replace_all(Element, [Head|List], NewElement, [Head|NewList]) :- replace_all(Element, List, NewElement, NewList).
“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 operatoris/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. • Removes any choice points that have been created since the predicate was invoked. • 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 …HeadN • Removes any choice points that may have been introduced in Goal1 … GoalN. • We will discuss Cut in more detail later on.
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).
Built-Ins: Term Comparison Operators • Unifies with • Term1 = Term2 iff unifies Term1 and Term2 if they are unifiable • Does not unify with • Term1 \= Term2, Term1 and Term2 are unchanged • Identical • Term1 == Term2 iff are the same terms • Not identical • Term1 \== Term2
Example: unify/2 (without occurs check) unify(Var1, Term2):- var(Var1), !, Var1 = Term2. unify(Term1, Var2):- var(Var2), !, Var2 = Term1. unify(Atomic1,Atomic2):- atomic(Atomic1), atomic(Atomic2), !, Atomic1 == Atomic2. unify(Term1, Term2):- compound(Term1), compound(Term2), functor(Term1, Functor, Arity), functor(Term2, Functor, Arity), unify_helper(Arity, Term1, Term2).
Example: unifiable/2 (continued) unify_helper(0, _Term1, _Term2):- !. unify_helper(Index, Term1, Term2):- arg(Index, Term1, Arg1), arg(Index, Term2, Arg2), unify(Arg1, Arg2), NextIndex is Index – 1, unify_helper(NextIndex, Term1, Term2).
Example: identical/2 identical(Var1, Var2):- var(Var1), var(Var2), !, Var1 == Var2. identical(Atomic1,Atomic2):- atomic(Atomic1), atomic(Atomic2), !, Atomic == Atomic2. identical(Term1, Term2):- compound(Term1), compound(Term2), functor(Term1, Functor, Arity), functor(Term2, Functor, Arity), identical_helper(Arity, Term1, Term2).
Example: identical/2 (continued) identical_helper(0, _Term1, _Term2):- !. identical_helper(Index, Term1, Term2):- arg(Index, Term1, Arg1), arg(Index, Term2, Arg2), identical(Arg1, Arg2), NextIndex is Index – 1, identical_helper(NextIndex, Term1, Term2).
Unification • Two terms unify iff there is a set of substitutions of variables with terms that makes the terms identical • True unification disallows cyclic terms: • X=f(X) ought to fail because there is no finite term that can substitute for X to make those terms identical. • This is called the occurs check. • Prolog unification does not enforce the occurs check, and may create cyclic terms • Occurs check is expensive • O(n) – n is the size of the smaller of the two terms • O(n+m) – n and m are the sizes of the two terms • In Prolog, it is quite typical to unify a variable with a larger term
Built-ins: true/0 and fail/0. • true. • Always succeeds. • fail. • Always fails.
Meta-Predicates: call/1, \+/1 • Meta-predicates take a Goal as an argument, and execute it. • call/1 executes it’s one argument. • \+(Goal) succeeds if call(Goal) fails. • \+/1 could also be defined using cut and fail. \+(Goal) :- call(Goal), !, fail. \+(_Goal).
Example: select/3 % select(+List, +Condition, -Element) select(List, Condition, Element):- member(Element, List), call(Condition). • This might be called with something like: • select([a, 5, c, 7], integer(Element), Element) • select([1,2,3,4,5,6,7], Element < 5, Element). • select([1,2,3,4,5,6,7], (0 is Element mod 2), Element)
More on non-logical predicates • \+ Goalis true if Goal fails. • \=, \==, and \+ introduce negation-as-failure • Not true negation, but failure-to-prove • A little bit of ‘non logical’ takes you a long way
Another way to write delete_all/3 delete_all(_Element, [], []). delete_all(Element, [Element|List], NewList) :- delete_all(Element, List, NewList). delete_all(Element, [Head|List], [Head|NewList]) :- Element \== Head, delete_all(Element, List, NewList).
Accumulators • Build up partial results to return at the end list_length([], 0). list_length([_Head|Tail], Result):- list_length(Tail, N), Result is N +1. list_length(List, Result) :- list_length_helper(List, 0, Result). list_length_helper([], Result, Result). list_length_helper([_Head|Tail], Partial, Result):- NextPartial is Partial + 1, list_length_helper(Tail, NextPartial, Result).
Acccumulators: 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).
Difference Lists • Use two logical variables that point to different portions of the same list. • Compare stacks with queues:
Stacks % empty_stack(?Stack) – true if Stack is empty empty_stack([]) % push(+Item, +Stack, -NewStack) push(Item, Stack, [Item|Stack]). %pop(+Stack, -Item, -NewStack) pop([Item|NewStack], Item, Stack).
Queues • Queue represented as a pair of lists (Front-Back) • Back is always a variable %empty_queue(?Queue) – true if the queue is empty empty_queue(Queue-Queue). %add_to_queue(+Element, +Queue, -NewQueue) add_to_queue(Element, (Front-[Element| Back]), (Front-Back)). %remove_from_queue(+Queue, -Element, -NewQueue) remove_from_queue(([Element|Front]-Back), Element, (Front-Back)).
Appending Difference Lists • Appending difference lists is very efficient append_dl((Front-Next), (Next-Back), (Front-Back)). • These uses of difference lists are incomplete data structures • Differenced lists are also useful as complete data structures • Considering using difference lists is situations where you might otherwise be doing a lot of appends.
Generate-and-Test • Popular (and sometimes efficient) way to write a program. Goal :- Generator, - generates candidate solutions Tester. - verifies correct answers
Example: select/3 % select(+List, +Condition, -Element) select(List, Condition, Element):- member(Element, List), - generates potential solutions call(Condition). - verifies that the meet the condition
Example: slow_sort/2 % slow_sort(+List, -SortedList) slow_sort(List, PermutedList):- permute(List, PermutedList), is_sorted(PermutedList). %permute(+List, -Permutation) permute([], []). permute([Head|Tail], Permutation):- permute(Tail, PermutedTail), insert(Head, PermutedTail, Permutation).
Example: slow_sort/2 (cont.) % insert(+Element, +List, -BiggerList) insert(Element, List, [Element|List]). insert(Element, [Head|List], [Head|BiggerList]):- insert(Element, List, BiggerList). % is_sorted(+List) is_sorted([]). is_sorted([_OneElement]). is_sorted([FirstElement, SecondElement|Tail]):- FirstElement =< SecondElement, is_sorted([SecondElement|Tail]).
Example: NPR Puzzle • Sunday morning’s weekly puzzle on KQED this week • Using a grid with 4 columns and 3 rows, find 3 four-letter words (along the rows) and 4 three-letter words (along the columns) that • Are all common words of English • Use each letter only once • Include all 6 vowels (a, e, i, o, u, y) • Assume two predicates: • three_letter_word(+First, +Second, +Third). • four_letter_word(+First, +Second, +Third, +Fourth).
NPR Puzzle (cont) npr_puzzle:- choose_four_letter_words([A,B,C,D, E,F,G,H, I,J,K,L]), test([A,B,C,D, E,F,G,H, I,J,K,L]). write(A),write(B),write(C),write(D),nl, write(E),write(F),write(G),write(H),nl, write(I),write(J),write(K),write(L),nl, nl, fail.
NPR Puzzle (cont) choose_four_letter_words([A,B,C,D, E,F,G,H, I,J,K,L]):- four_letter_word(A,B,C,D), four_letter_word(E,F,G,H), unique_letters([E,F,G,H], [A,B,C,D]), four_letter_word(I,J,K,L), unique_letters([I,J,K,L], [A,B,C,D,E,F,G,H]). unique_letters([], _). unique_letters([A|Rest], Letters):- \+ member(A, Letters), unique_letters(Rest,Letters).
NPR Puzzle (cont) test([A,B,C,D, E,F,G,H, I,J,K,L]):- three_letter_word(A,E,I), three_letter_word(B,F,J), three_letter_word(C,G,K), three_letter_word(D,H,L), uses_all_vowels([A,B,C,D, E,F,G,H, I,J,K,L]),
NPR Puzzle (cont) uses_all_vowels(Letters):- member(a, Letters), member(e, Letters), member(i, Letters), member(o, Letters), member(u, Letters), member(y, Letters).
NPR Puzzle Results • After some futzing to get good lists of 3 and 4 letter words, and about 4 CPU hours, we get one solution: peas omit duly
Homework • By now, we have covered most of Chapters 3 and 4 of Clocksin and Mellish. Read them and let me know if you have any questions. • Homework to be handed in by noon on the 29th.