Prolog for Linguists Symbolic Systems 139P/239P
-
Upload
abdul-england -
Category
Documents
-
view
29 -
download
0
description
Transcript of Prolog for Linguists Symbolic Systems 139P/239P
Prolog for LinguistsSymbolic Systems 139P/239P
John Dowding
Week 5, Novembver 5, 2001
Office Hours
We have reserved 4 workstations in the Unix Cluster in Meyer library, fables 1-4
4:30-5:30 on Thursday this week
Or, contact me and we can make other arrangements
Course Schedule
1. Oct. 82. Oct. 153. Oct. 224. Oct. 295. Nov. 5 (double up)6. Nov. 127. Nov. 26 (double up)8. Dec. 3
No class on Nov. 19
More about cut!
Common to distinguish between red cuts and green cuts Red cuts change the solutions of a predicate Green cuts do not change the solutions, but effect the efficiency
Most of the cuts we have used so far are all red cuts
%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).
Green cuts
Green cuts can be used to avoid unproductive backtracking% identical(?Term1, ?Term2)identical(Var1, Var2):-
var(Var1), var(Var2),!, Var1 == Var2.
identical(Atomic1,Atomic2):- atomic(Atomic1), atomic(Atomic2),!, Atomic1 == Atomic2.
identical(Term1, Term2):-compound(Term1),compound(Term2),functor(Term1, Functor, Arity),functor(Term2, Functor, Arity),identical_helper(Arity, Term1, Term2).
Input/Output of Terms
Input and Output in Prolog takes place on StreamsBy default, input comes from the keyboard, and output goes to the screen.Three special streams: user_input user_output user_error
read(-Term)write(+Term)nl
Example: Input/Output
repeat/0 is a built-in predicate that will always resucceed
% classifing terms
classify_term :-
repeat,
write('What term should I classify? '),
nl,
read(Term),
process_term(Term),
Term == end_of_file.
Streams
You can create streams with open/3
open(+FileName, +Mode, -Stream)
Mode is one of read, write, or append.
When finished reading or writing from a Stream, it should be closed with close(+Stream)
There are Stream-versions of other Input/Output predicates read(+Stream, -Term) write(+Stream, +Term) nl(+Stream)
Characters and character I/O
Prolog represents characters in two ways: Single character atoms ‘a’, ‘b’, ‘c’ Character codes
Numbers that represent the character in some character encoding scheme (like ASCII)
By default, the character encoding scheme is ASCII, but others are possible for handling international character sets.Input and Output predicates for characters follow a naming convention: If the predicate deals with single character atoms, it’s name ends in _char. If the predicate deals with character codes, it’s name ends in _code.
Characters are character codes is traditional “Edinburgh” Prolog, but single character atoms were introduced in the ISO Prolog Standard.
Special Syntax I
Prolog has a special syntax for typing character codes: 0’a is a expression that means the character codc that represents
the character a in the current character encoding scheme.
Special Syntax II
A sequence of characters enclosed in double quote marks is a shorthand for a list containing those character codes.
“abc” = [97, 98, 99]
It is possible to change this default behavior to one in which uses single character atoms instead of character codes, but we won’t do that here.
Built-in Predicates:
atom_chars(Atom, CharacterCodes) Converts an Atom to it’s corresponding list of character codes, Or, converts a list of CharacterCodes to an Atom.
put_code(Code) and put_code(Stream, Code) Write the character represented by Code
get_code(Code) and get_code(Stream, Code) Read a character, and return it’s corresponding Code
Checking the status of a Stream: at_end_of_file(Stream) at_end_of_line(Stream)
Review homework problems: last/2
% last(?Element, ?List)
last(Element, [Element]).
last(Element, [_Head|Tail]):-
last(Element, Tail).
Or
last(Element, List):-
append(_EverthingElse, [Element], List).
evenlist/1 and oddlist/1
%evenlist(?List).
evenlist([]).
evenlist([_Head|Tail]):-
oddlist(Tail).
%oddlist(+List)
oddlist([_Head|Tail]):-
evenlist(Tail).
palindrome/1
%palindrome1(+List).
palindrome1([]).
palindrome1([_OneElement]).
palindrome1([Head|Tail]):-
append(Rest, [Head], Tail),
palindrome1(Rest).
Or, palindrome/1
%palindrome(+List)palindrome(List):- reverse(List, List).
%reverse(+List, -ReversedList)reverse(List, ReversedList):- reverse(List, [], ReversedList).
%reverse(List, Partial, ReversedList)reverse([], Result, Result).reverse([Head|Tail], Partial, Result):- reverse(Tail, [Head|Partial], Result).
subset/2
%subset(?Set, ?SubSet)
subset([], []).
subset([Element|RestSet], [Element|RestSubSet]):-
subset(RestSet, RestSubSet).
subset([_Element|RestSet], SubSet):-
subset(RestSet, SubSet).
union/3
%union(+Set1, +Set2, -SetUnion)
union([], Set2, Set2).
union([Element|RestSet1], Set2, [Element|SetUnion]):-
union(RestSet1, Set2, SetUnion),
\+ member(Element, SetUnion),
!.
union([_Element|RestSet1], Set2, SetUnion):-
union(RestSet1, Set2, SetUnion).
intersect/3
%intersect(+Set1, +Set2, ?Intersection)
intersect([], _Set2, []).
intersect([Element|RestSet1], Set2, [Element|Intersection]):-
member(Element, Set2),
!,
intersect(RestSet1, Set2, Intersection).
intersect([_Element|RestSet1], Set2, Intersection):-
intersect(RestSet1, Set2, Intersection).
split/4
%split(+List, +SplitPoint, -Smaller, -Bigger).
split([], _SplitPoint, [], []).
split([Head|Tail], SplitPoint, [Head|Smaller], Bigger):-
Head =< SplitPoint,
!, % green cut
split(Tail, SplitPoint, Smaller, Bigger).
split([Head|Tail], SplitPoint, Smaller, [Head|Bigger]):-
Head > SplitPoint,
split(Tail, SplitPoint, Smaller, Bigger).
merge/3
%merge(+List1, +List2, -MergedList)
merge([], List2, List2).
merge(List1, [], List1).
merge([Element1|List1], [Element2|List2], [Element1|MergedList]):-
Element1 =< Element2,
!,
merge(List1, [Element2|List2], MergedList).
merge(List1, [Element2|List2], [Element2|MergedList]):-
merge(List1, List2, MergedList).
Sorting: quicksort/2
% quicksort(+List, -SortedList)
quicksort([], []).
quicksort([Head|UnsortedList], SortedList):-
split(UnsortedList, Head, Smaller, Bigger),
quicksort(Smaller, SortedSmaller),
quicksort(Bigger, SortedBigger),
append(SortedSmaller, [Head|SortedBigger], SortedList).
Sorting: mergesort/2
% mergesort(+List, -SortedList).
mergesort([], []).
mergesort([_One], [_One]):-
!.
mergesort(List, SortedList):-
break_list_in_half(List, FirstHalf, SecondHalf),
mergesort(FirstHalf, SortedFirstHalf),
mergesort(SecondHalf, SortedSecondHalf),
merge(SortedFirstHalf, SortedSecondHalf, SortedList).
Merge sort helper predicates
% break_list_in_half(+List, -FirstHalf, -SecondHalf)break_list_in_half(List, FirstHalf, SecondHalf):-
length(List, L),HalfL is L /2,first_n(List, HalfL, FirstHalf, SecondHalf).
% first_n(+List, +N, -FirstN, -Remainder)first_n([Head|Rest], L, [Head|Front], Back):-
L > 0,!,NextL is L - 1,first_n(Rest, NextL, Front, Back).
first_n(Rest, _L, [], Rest).
Lexigraphic Ordering
We can extending sorting predicates to sort all Prolog terms using a lexigraphic ordering on terms.
Defined recursively: Variables @< Numbers @< Atoms @< CompoundTerms Var1 @< Var2 if Var1 is older than Var2 Atom1 @< Atom2 if Atom1 is alphabetically earlier than Atom2. Functor1(Arg11, … Arg1N) @< Functor2(Arg21,…, Arg2M) if
Functor1 @< Functor2, or Functor1 = Functor2 and N @< M, or Functor1=Functor2, N=M, and Arg11 @< Arg21, or Arg11 @= Arg21 and Arg12 @< Arg22, or …
Built-in Relations:
Less-than @<
Greater than @>
Less than or equal @=<
Greater than or equal @>=
Built-in predicate sort/2 sorts Prolog terms on a lexigraphic ordering.
Tokenizer
A token is a sequence of characters that constitute a single unit
What counts as a token will vary A token for a programming language may be different from a
token for, say, English.
We will start to write a tokenizer for English, and build on it in further classes
Homework
Read section in SICTus Prolog manual on Input/OutputThis material corresponds to Ch. 5 in Clocksin and Mellish, but the Prolog manual is more up to date and consistent with the ISO Prolog Standard
Improve the tokenizer by adding support for contractions can’t., won’t haven’t, etc. would’ve, should’ve I’ll, she’ll, he’ll He’s, She’s, (contracted is and contracted has, and possessive)
Don’t hand this in, but hold on to it, you’ll need it later.
My tokenizer
First, I modified to turn all tokens into lower case
Then, added support for integer tokens
Then, added support for contraction tokens
Converting character codes to lower case
% occurs_in_word(+Code, -LowerCaseCode)
occurs_in_word(Code, Code):-
Code >= 0'a,
Code =< 0'z.
occurs_in_word(Code, LowerCaseWordCode):-
Code >= 0'A,
Code =< 0'Z,
LowerCaseWordCode is Code + (0'a - 0'A).
Converting to lower case
% case for regular word tokensfind_one_token([WordCode|CharacterCodes], Token, RestCharacterCodes):-
occurs_in_word(WordCode, LowerCaseWordCode),find_rest_word_codes(CharacterCodes, RestWordCodes, RestCharacterCodes),atom_chars(Token, [LowerCaseWordCode|RestWordCodes]).
find_rest_word_codes(+CharacterCodes, -RestWordCodes, -RestCharacterCodes)find_rest_word_codes([WordCode|CharacterCodes], [LowerCaseWordCode|RestWordCodes],
RestCharacterCodes):-occurs_in_word(WordCode, LowerCaseWordCode),!, % red cutfind_rest_word_codes(CharacterCodes, RestWordCodes, RestCharacterCodes).
find_rest_word_codes(CharacterCodes, [], CharacterCodes).
Adding integer tokens
% case for integer tokensfind_one_token([DigitCode|CharacterCodes], Token, RestCharacterCodes):- digit(DigitCode), find_rest_digit_codes(CharacterCodes, RestDigitCodes, RestCharacterCodes), atom_chars(Token, [DigitCode|RestDigitCodes]).
% find_rest_digit_codes(+CharacterCodes, -RestDigitCodes, -RestCharacterCodes)find_rest_digit_codes([DigitCode|CharacterCodes], [DigitCode|RestDigitCodes],
RestCharacterCodes):-digit(DigitCode),!, % red cutfind_rest_digit_codes(CharacterCodes, RestDigitCodes, RestCharacterCodes).
find_rest_digit_codes(CharacterCodes, [], CharacterCodes).
Digits
%digit(+Code)
digit(Code):-
Code >= 0'0,
Code =< 0'9.
Contactions
Turned unambiguous contractions into the corresponding English wordLeft ambiguous contractions contracted.Handled 2 cases Simple contractions:
He’s => He + ‘sHe’ll => He + willThey’ve => They + have
Exceptionscan’t => can + notwon’t => will + not
Simple Contractions
simple_contraction("'re", "are").
simple_contraction("'m", "am").
simple_contraction("'ll", "will").
simple_contraction("'ve", "have").
simple_contraction("'d", "'d"). % had, would
simple_contraction("'s", "'s"). % is, has, possessive
simple_contraction("n't", "not").
handle_contractions/2
% handle_contractions(+TokenChars, -FrontTokenChars, RestTokenChars)
handle_contractions("can't", "can", "not"):-
!.
handle_contractions("won't", "will", "not"):-
!.
handle_contractions(FoundCodes, Front, NewCodes):-
simple_contraction(Contraction, NewCodes),
append(Front, Contraction, FoundCodes),
Front \== [],
!.
Modify find_one_token/3
% case for regular word tokensfind_one_token([WordCode|CharacterCodes], Token, RestCharacterCodes):-
occurs_in_word(WordCode, LowerCaseWordCode),
find_rest_word_codes(CharacterCodes, RestWordCodes, TempCharacterCodes),
handle_contractions([LowerCaseWordCode|RestWordCodes], FirstTokenCodes, CodesToAppend),
append(CodesToAppend, TempCharacterCodes, RestCharacterCodes),
atom_chars(Token, FirstTokenCodes).
Dynamic predicates and assert
Add or remove clauses from a dynamic predicate at run time.To specify that a predicate is dynamic, add
:- dynamic predicate/Arity.to your program.assert/1 adds a new clauseretract/1 removes one or more clausesretractall/1 removes all clauses for the predicateCan’t modify compiled predicates at run timeModifying a program while it is running is dangerous
assert/1, asserta/1, and assertz/1
Asserting facts (most common)assert(Fact)
Asserting rulesassert( (Head :- Body) ).
asserta/1 adds the new clause at the front of the predicate
assertz/1 adds the new clause at the end of the predicate
assert/1 leaves the order unspecified
Built-In: retract/1
retract(Goal) removes the first clause that matches Goal.
On REDO, it will remove the next matching clause, if any.
Retract facts:retract(Fact)
Retract rules:retract( (Head :- Body) ).
Built-in: retractall/1
retractall(Head) removes all facts and rules whose head matches.
Could be implemented with retract/1 as:
retractall(Head) :-
retract(Head),
fail.
retract(Head):-
retract( (Head :- _Body) ),
fail.
retractall(_Head).
Built-In: abolish(Predicate/Arity)
abolish(Predicate/Arity) is almost the same as
retract(Predicate(Arg1, …, ArgN))
except that abolish/1 removes all knowledge about the predicate, where retractall/1 only removes the clauses of the predicate.
That is, if a predicate is declared dynamic, that is remembered after retractall/1, but not after abolish/1.
Example: Stacks & Queues
:- dynamic stack_element/1.empty_stack :- retractall(stack_selement(_Element)).
% push_on_stack(+Element)push_on_stack(Element):- asserta(stack_element(Element)).
% pop_from_stack(-Element)pop_from_stack(Element):- var(Element), retract(stack_element(Element)), !.
Queues
% dynamic queue_element/1.empty_queue :- retractall(queue_element(_Element)).
%put_on_queue(+Element)put_on_queue(Element):- assertz(queue_element(Element)).
%remove_from_queue(-Element)remove_from_queue(Element):- var(Element), retract(queue_element(Element)), !.
Example: prime_number.
:- dynamic known_prime/1.
find_primes(Prime):-
retractall(known_prime(_Prime)),
find_primes(2, Prime).
find_primes(Integer, Integer):-
\+ composite(Integer),
assertz(known_prime(Integer)).
find_primes(Integer, Prime):-
NextInteger is Integer + 1,
find_primes(NextInteger, Prime).
Example: prime_number (cont)
%composite(+Integer)
composite(Integer):-
known_prime(Prime),
0 is Integer mod Prime,
!.
Aggregation: findall/3.
findall/3 is a meta-predicate that collects values from multiple solutions to a Goal:
findall(Value, Goal, Values)
findall(Child, parent(james, Child), Children)
Prolog has other aggregation predicates setof/3 and bagof/3, but we’ll ignore them for now.
findall/3 and assert/1
findall/3 and assert/1 both let you preserve information across failure.:- dynamic solutions/1.findall(Value, Goal, Solutions):-
retractall(solutions/1),assert(solutions([])),call(Goal),retract(solutions(S)),append(S, [Value], NextSolutions),assert(solutions(NextSolutions)),fail.
findall(_Value, Goal, Solutions):-solutions(Solutions).
Special Syntax III: Operators
Convenience in writing terms
We’ve seem them all over already:union([Element|RestSet1], Set2, [Element|SetUnion]):-
union(RestSet1, Set2, SetUnion),
\+ member(Element, SetUnion),
!.
This is just an easier way to write the term:‘:-’(union([Element|RestSet],Set2,[Element|SetUnion]),
‘,’(union(RestSet1,Set2,SetUnion),
‘,’(‘\+’(member(Element, SetUnion),
!)))
Operators (cont)
Operators can come before their arguments (prefix) \+, dynamic
Or between their arguments (infix) , + is <
Of after their arguments (postfix) Prolog doesn’t use any of these (yet)
The same Operator can be more than one type :-
Precedence and Associativity
Operators also have precedence 5 * 2 + 3 = (5 * 2) + 3
Operators can be associative, or not,
Left associative or right associative
Explicit parenthesization can override defaults for associatiativity and precendence
Built-in: current_op/3
current_op/3 gives the precedence and associativity of all current operators.
current_op(Precedence, Associativity, Operator)
where Precedence in an integer 1-1200
and Associativity is of fx or fy for prefix operators xf or yf for postfix operators xfx, xfy, yfx, yfy for infix operators
Associativity
These atoms: fx, fy, xf, yf, xfx, xfy, yfx, yfy draw a “picture” of the associativity of the operator: The location of the f tells if the operator is prefix, infix,
or postfix. x means that the argument must be of lower precedence y means that the argument must be of equal or lower
precedence. A y on the left means the operator is left associative A y on the right means the operator is right associative
Operator Examples
Precedence Associativity Operator
1200 xfx :-
1150 fx dynamic
1000 xfy ,
900 fy \+
700 xfx =
700 xfx is
700 xfx <
500 yfx +
500 fx +
400 yfx *
300 xfx mod
Creating new operators
Built-in op/3 creates new operators
op(+Precedence, +Associativity, +Operator)
:- op(700, xfx, equals).
:- op(650, fx, $).
:- op(650, xf, cents).
$Dollars equals Cents cents :-
Cents is 100 * Dollars.
Consult
The operation for reading in a file of Prolog clauses and treating them as a program is traditional known as “consulting” the file.
We will write a simple consult/1 predicate, and build on it over time.
We will write similar
Consult (cont)
consult_file(File):-
open(File, read, Stream),
consult_stream(Stream),
close(Stream).
consult_stream(Strea):-
repeat,
read(Stream, Term),
consult_term(Term),
at_end_of_stream(Stream),
!.
Consult (cont)
consult_term((:- Goal)):-
!,
call(Goal).
consult_term((Goal :- Body)):-
!,
assertz((Goal :- Body)).
consult_term(Fact):-
assertz(Fact).
Parsing, grammars, and language theory
The development of Prolog (by Colmeraur at Marseilles) was motivated in part by a desire to study logic and language.
Grammars are formal specifications of languages
Prolog takes these specifications and treats them as logical theories about language, and as computations
Grammar Proof Computation
Pereira and Warren, Parsing as Deduction, 1984.
Ideas from Prolog/Logic Programming, particularly unification, are found in modern Linguistics.
Overview of formal language theory
An Alphabet is a set of symbols
A Sentence is a finite sequence of symbols from some alphabet
A Language L is a (potentially infinite) set of sentences from some alphabet
A Grammar is a finite description of a language
L(G) is the language described by the grammar G
We will be interested in several problems: Is a given sentence a member of L(G)? What structure does G assign to the sentence?
Context-Free Grammars
A Context-Free Grammar consists of: An alphabet A set of nonterminal symbols N (N=) A distinguished start symbol SN A set of production rules of the form:
A B1 … BN, where A N and B1 … BN (N )
CFG: example
S NP VPNP DET NVP V VP V NPDET theDET aN manN menN womanN women
N catN catsN dogN dogsV likeV likesV sleepV sleeps
Derivations
S => NP VP=> DET N VP=> the N VP=> the man VP=> the man V NP=> the man likes NP=> the man likes DET N=> the man likes the N=> the man likes the woman
A Prolog Program for that CFG
s(S) :- np(NP), vp(VP), append(NP, VP, S).
np(NP) :- det(DET), n(N), append(DET, N, NP).
vp(VP) :- v(V), V=VP.
vp(VP) :- v(V), np(NP),
append(V, NP, VP).
det([the]).
det([a]).
n([man]).
n([men]).
n([woman]).
n([women]).
n([cat]).
n([cats]).
n([dog]).
n([dogs]).
v([like]).
v([likes]).
v([sleep]).
v([sleeps]).
Automatically generating that grammar
We can define an operator to define grammar rules,
And update consult_file/1 to translate them into Prolog clauses automatically
These facilities are already built into the built-in consult/1, but we will build them ourselves
Updates to consult_file
:- op(1200, xfx, '-->').
% Add a new clause to consult_term/1
consult_term((NT --> Rule)):-
!,
grammar_rule_body(Rule, Body, Phrase),
functor(Goal, NT, 1),
arg(1, Goal, Phrase),
assertz((Goal :- Body))
grammar_rule_body/3
grammar_rule_body((Rule1, Rule2),(Body1, Body2, append(Phrase1, Phrase2, Phrase)), Phrase):-!,grammar_rule_body(Rule1, Body1, Phrase1),grammar_rule_body(Rule2, Body2, Phrase2).
grammar_rule_body(List, true, List):-is_list(List),!.
grammar_rule_body(NT, Goal, Phrase):-atom(NT),functor(Goal, NT, 1),arg(1, Goal, Phrase).
The grammar can now look like this:
s --> np, vp.
np --> det, n.
vp --> v.
vp --> v, np.
det --> [the].
det --> [a].
n --> [man].
n --> [men].
n --> [woman].
n --> [women].
n --> [dog].
n --> [dogs].
v --> [like].
v --> [likes].
v --> [sleep].
v --> [sleeps].
A better way to do the translation
So, we can transform the grammar into a program automatically,
But, it’s not a very good program
We could try to move the assert/3 around, but that would not be very reversible.
Instead, use difference lists Use two variables, one to keep track of the start of each
phrase, and one to keep track of it’s end.
Difference lists as indicies
Traditional parsing uses indicies to keep track of phrase boundaries
the man likes the dog 0 1 2 3 4 5
“the man” is an NP spanning 0-2“likes the dog” is a VP spanning 2-5We’ll use difference lists to indicate spans,“the dog” is an NP spanning [the,dog]-[]“the man” is an NP spanning [the,man,likes,the,dog]-[likes,the,dog]
Difference list grammar rule translation
s np, vp.
Translates to:
s(S0, SN) :- np(S0, S1), vp(S1, SN).
Instead of one variable, we have two, for the start and end points of the phrase,And the phrases are linked so that the end of one phrase is the same as the start of the adjacent phrase.
Ruling out ungrammatical phrases
We’ve got a little grammar, but it accepts a lot of ungrammatical sentences
First, let’s deal with number agreement between subject NP and the verb:
Conventional to indicate ungrammatical sentences with a *
The man sleeps.
*The man sleep.
We *could* just add more rules…
s np_sing, vp_sings np_plural, vp_plural.np_sing det, n_sing.np_plural det, n_plural.vp_sing v_sing.vp_plural v_plural.vp_sing v_sing np_sing.vp_sing v_sing np_plural.vp_plural v_plural, np_sing.vp_plural v_plural, np_plural.det [the].det [a].
n_sing [man].n_sing [woman].n_sing [cat].n_sing [dog].n_plural [men].n_plural [women].n_plural [cats].n_plural [dogs].v_sing [likes].v_sing [sleeps].v_plural [like].v_plural [likes].
Features
But, this leads to duplicating a lot of rulesWhat if we want to eliminate other ungrammatical sentences: Number agreement between determiner and noun Transitive and Intransitive verbs
A man sleeps.*A men sleep.The men like the cat.*The men like.The men sleep.*The men sleep the cat.
Features
We can add features on rules to express these constraints concisely.
s(Number) np(Number), vp(Number).np(Number) det(Number), n(Number).vp(Number) v(Number, intranitive).vp(Number) v(Number, transitive), np(_).det(singular) [a].det(_) [the].n(singular) [man].n(plural) [men].v(singular, transitive) [likes].v(singular, intransitive) [sleeps].
Improved Consult
consult_term((NT --> Rule)):-!,grammar_rule_body(Rule, Body, Start, End),make_nonterminal(NT, Start, End, Goal),assertz((Goal :- Body)).
make_nonterminal(NT, Start, End, Goal):-NT =.. List,append(List, [Start,End], FullList),Goal =.. FullList.
Improved Consult (cont)
grammar_rule_body((Rule1, Rule2),(Body1, Body2), Start, End):-
!,
grammar_rule_body(Rule1, Body1, Start, Next),
grammar_rule_body(Rule2, Body2, Next, End).
grammar_rule_body(List, true, Start, End):-
is_list(List),
!,
append(List, End, Start).
grammar_rule_body(NT, Goal, Start, End):-
make_nonterminal(NT, Start, End, Goal).
Possible Class Projects
Should demonstrate competence in Prolog programming
Expect problems with solutions in 5-20 pages of code range.
Talk/email with me about your project
Information extraction from a web page
Pick a web page with content that might be well represented in a Prolog database: Sports statistics TV listings
Write a program to parse the HTML, extract the relevant information, and turn it into a Prolog database.
Question-Answering
Write a program to accept user’s questions typed at the keyboard, parse them, and generate answers from a known database.
Breadth-first Prolog interpreter
Write a breadth-first Prolog interpreter
Test it with some simple programs, and compare it with depth-first Prolog, and iterative deepening.
Compare/contrast with LP language
Select another logical programming language Mercury, Eclipse, etc.
Test a variety of the kinds of programs we have written in this class (generate-and-test, DCGs, etc.), and see how they would be written.
Only consider this if you are confident that you have already demonstrated Prolog competence.
What to cover in remaining weeks
We’ve got 4 more “sessions”, I have these plans: Another session on DCGs A session on iterative deepening Some time on logical foundations/theorem proving
Any thoughts on other things you’ld like to cover?
More review?
Help with class projects?