Combining Description Logic, Autoepistemic Logic and Logic Programming
Logic Programming
description
Transcript of Logic Programming
Logic ProgrammingLogic Programming
Nai-Wei LinDepartment of Computer Science and Information
EngineeringNational Chung Cheng
University
Outline• An introduction to logic
– Predicate calculus– Horn clauses– Unification and resolution
• Basic Prolog programming– Syntax of Prolog– Control in Prolog – Data structures in Prolog
• Advanced Prolog programming– Cut– Negation– Higher-order predicates– Incomplete data structures
Logic Programming
• Logic programming uses logic as a
programming language
• Logic programming computes relations
instead of functions
• Logic programming is declarative
programming
Relations and Functions
Let A and B be sets• A relation from A to B is a subset of A × B.• A function from A to B is a relation R from A to
B such that for each a A, there exists one and only one b B such that (a,b) R.
• Functions are special cases of relations.• Example: A = {a1, a2, a3, a4} B = {b1, b2, b3} R = {(a1,b1), (a2,b2), (a2,b3), (a4,b3)} F = {(a1,b1), (a2,b2), (a3,b3), (a4,b3)}
Propositions
1. Boolean values true and false are propositions.
2. A symbol is a proposition which has value
true or false.
3. If p and q are propositions, then so are (a) p: negation of p,(b) p q: conjunction of p and q,(c) p q: disjunction of p and q, and (d) p q: implication from p to q.
Predicates1. Each predicate denotes a relation among constants.2. Each predicate is defined as a set of terms.3. Terms are relation instances whose arguments can be
constants or existential quantified () or universal quantified () variables
Examples: parent(ted, derek). parent(ted, dena). parent(ted, dustin). parent(derek, adams). X,Y.(parent(X,Y) ancestor(X, Y)). X,Y.(Z.parent (X,Z) ancestor(Z,Y) ancestor(X,Y)).
Theorem Proving
• Predicates as axioms
• Queries as theorems
• Answering queries as proving theorems
An Example
parent(ted, derek).
parent(ted, dena).
parent(ted, dustin).
parent(derek, adams).
X,Y.(parent(X,Y) ancestor(X, Y)).
X,Y.( Z.parent(X, Z) ancestor(Z, Y) ancestor(X, Y)).
parent(ted, derek)?
X.parent(ted, X)?
X,Y.parent(X, Y)?
X.ancestor(ted, X)?
Resolution Inference Rule
• Predicates as axioms• Queries as theorems• Resolution as the inference rule
p, p q ┝ q• Proving theorems by backward deduction
Horn Clauses
• The set of Horn clauses is a subset of predicate calculus
• Each of the implication in the Horn clauses is in the form of p1 ,…, pn q where n 0
• Resolution inference rule can be efficiently used only for Horn clauses
A Notation for Horn Clauses
Facts (universal): <fact> ::= <term>. parent(ted, derek).
Rules (universal or existential): <rule>::= <term> :- <terms>. ancestor(X, Y) :- parent(X, Y). ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
Queries (existential): <query> ::= ?- <terms>. ?- parent(ted, X). ?- ancestor(ted, X).
Clauses and Predicates
• A clause is a fact or a rule• A literal is a relation occurrence in a clause• Clause head is the literal before ‘ :- ’ in a clause• Clause body consists of the literals after ‘ :- ’ in a clause• A predicate is the set of clauses whose head has the same predicate symbol and arity (number of arguments)
An Example
parent(ted, derek).
parent(ted, dena).
parent(ted, dustin).
parent(derek, adams).
ancestor(X, Y) :- parent(X,Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).
Substitution• A substitution is a function from variables to terms {X → ted, Y → derek}
• Rules for applying a substitution σ to a term: 1. σ(X) = U, if X →U is in σ 2. σ(X) = X, otherwise 3. σ(f(T1,T2)) = f(U1,U2), if σ(T1) = U1, σ(T2) = U2
{X → ted, Y → derek}(X) = ted {X → ted, Y → derek}(Z) = Z {X → ted, Y → derek}(parent(X,Y)) = parent(ted,derek)
Instances
• A term U is an instance of a term T if U = σ(T) for some substitution σ
parent(ted,derek) is an instance of parent (X, derek)
parent(X,derek) is an instance of parent (X, Y)
Unification
• Terms T1 and T2 unify if σ(T1) = σ(T2) for some substitution σ
• Substitution σ is called a unifier of T1 and T2.
{H → a, T → b} (f(a , T))
= {H → a, T → b} (f(H, b))
= f(a, b)
Most General Unifier
• Substitution σ is the most general unifier of T1 and T2 if for all other unifiers σ’ , σ’ (T1) is an instance of σ(T1).
{X1 → a, X2 → Z, Y1 → a, Y2 → Z }(f(X1,X2,c))
= {X1 → a, X2 → Z, Y1 → a, Y2 → Z }(f(Y1,Y2,c))
= f(a, Z, c)
{X1 → a, X2 → b, Y1 → a, Y2 → b }(f(X1,X2,c))
= {X1 → a, X2 → b, Y1 → a, Y2 → b }(f(Y1,Y2,c))
= f(a, b, c)
{Z → b}(f(a, Z, c)) = f(a, b, c)
Resolution
Let
Qi = a1, a2, …, an
be a query and
b :- b1, b2, …, bm
be a rule.
If σis the most general unifier of a1 and b, and
Qi+1 = σ(b1, b2, …, bm, a2, …, an),
then we say Qi is reduced to Qi+1 via a resolution
step.
An Example
The most general unifier for the query
ancestor (X, adams)
and the rule
ancestor (X, Y) :- parent (X, Y)
is
σ = {Y → adams }
Hence, the query after the resolution of these two
is
σ(parent(X, Y)) = parent(X, adams)
Computation• A computation for a query Q with respect to a
set of predicates is a (possibly infinite) sequence of queries Q = Q0, …, Qi, Qi+1, …
such that each Qi is reduced to the query Qi+1
via a resolution step.
?- ancestor(X, adams). ?- parent(X, adams). true
σ = {Y → adams}
σ = {X → derek}
Computation
• If a computation C has an infinite sequence of queries, then C does not terminate.
• If a computation C with queries Q0, …, Qn
is maximal, and Qn = true, then C is said to succeed with answer substitution
n … 1
restricted to the variables occurring in Q0.• Otherwise, C is said to fail.
An Example• ?- ancestor (X, adams).
ancestor (X, Y) :- parent (X, Y).
σ1 = {Y → adams}
σ1(parent(X, Y)) = parent(X, adams)
?- parent(X, adams).• ?- parent (X, adams).
parent (derek,adams).
σ2 = {X → derek}
true σ = σ2 σ1 = {X → derek, Y → adams}
= {X → derek}
Prolog
• Prolog is a general programming language for
logic programming
• Prolog also includes some imperative
features for efficiency
• Prolog uses the same syntactic form for both
programs and data
Prolog
• The first Prolog system was developed in early 1970’s by Alain Colmerauer and his group at the University of Marseille-Aix as a specialized theorem prover for natural language processing.
• The first efficient Prolog was developed in late 1970’s by David Warren and his group in University of Edinburgh.
Prolog SyntaxTerms:
< term > ::= < number > | < variable >
| < symbol > | < symbol > (<terms>)
< terms > ::= < term > | < term > , < terms >
Examples: 1, 1994 N, N1, _, _1 ted, derek parent(X, Y) +(2, *(3, 4)), 2 + 3 * 4
A Typical Session?- consult( ‘family.pl’).yes
?- parent(ted,derek).yes
?- parent(ted,X).X = derek;X = dena;X= dustin;no
?- parent(ted, X).X = derekyes
return next solution
stop returning solutions
A Typical Session?- parent(X, Y).X = ted, Y = derek;X = ted, Y = dena;X = ted, Y = dustin;X = derek, Y = adams;no
?- ancestor(X, Y).X = ted, Y = derek;X = ted, Y = dena;X = ted, Y = dustin;X = derek, Y = adams;X = ted, Y = adams;no
?- halt.
Control in Prolog
• Try clauses from top to bottom
• Resolve literals from left to right
An Example
parent(ted, derek). parent(ted, dena).parent(ted, dustin).parent(derek, adams). ?- parent(ted,X).X = derek;X = dena;X = dustin;no
parent(ted,X).
σ1 = {X→derek}
true
σ2 = {X→dena}
true
σ3 = {X→dustin}
true
false
An Exampleparent (ted, derek).parent (derek, adams).ancestor(X, Y) :- parent(X, Y).ancestor(X, Y) :- parent (X, Z), ancestor (Z, Y).
?- ancestor (X, adams).
σ1 = {X → X_1, Y_1 → adams}
σ1(parent(X_1, Y_1)) = parent (X_1, adams) ?- parent (X_1, adams).
σ2 = {X_1 → derek}
σ = σ2 σ1 = {X → derek} X = derek; (succeed)
An Example
ancestor(X,adams).
σ1 = {X→X_1,Y_1→adams} σ1 = {X→X_1,Y_1→adams}
parent (X_1, adams).
σ2 = {X_1 → derek}
truefalse
parent(X_1, Z_1), ancestor(Z_1, adams)).
An Example?- ancestor(X, adams).
σ1 = {X X_1, Y_1 adams}
σ1(parent(X_1, Z_1), ancestor(Z_1, Y_1))
= parent(X_1, Z_1), ancestor(Z_1, adams))
?- parent(X_1, Z_1), ancestor(Z_1, adams).
σ2 = {X_1 ted, Z_1 derek}
σ2(ancestor(Z_1, adams)) = ancestor(derek, adams)
?- ancestor(derek, adams).
σ3 = {X_2 derek, Y_2 adams}
σ3(parent(X_2, Y_2)) = parent(derek, adams)
?- parent(derek, adams). σ4 = { }
σ = σ4 σ3 σ2 σ1
= {X,X_1ted, Y_1,Y_2adams, Z_1,X_2derek}
X = ted; (succeed)
An Example
parent(X_1, Z_1), ancestor(Z_1, adams).
σ2 = {X_1 ted, Z_1 derek}
ancestor(derek, adams).
truefalse
parent(derek, adams).
σ4 = { }
σ3 = {X_2 derek, Y_2 adams}
σ2 = {X_1 derek, Z_1 adams}
ancestor(adams, adams).
σ3 = {X_2 derek, Y_2 adams}
parent(derek, Z_2), ancestor(Z_2, adams).
An Example?- ancester(derek, adams).
σ3 = {X_2 derek,Y_2 adams}
σ3(parent(X_2, Z_2), ancestor(Z_2, Y_2)) = parent(derek, Z_2), ancestor(Z_2, adams)?- parent(derek, Z_2), ancestor(Z_2, adams).
σ4 = {Z_2 adams}
σ4(ancestor(Z_2, adams)) = ancestor(adams, adams)?- ancestor(adams, adams).
σ5 = {X_3adams,Y_3adams}
σ5(parent(X_3, Y_3)) = parent(adams, adams)?- parent(adams, adams).(fail)
An Example
parent(derek, Z_2), ancestor(Z_2, adams).
σ4 = {Z_2 adams}
ancestor(adams, adams).
false false
parent(adams, adams).σ5 = {X_3adams,Y_3adams}
false
σ5 = {X_3adams,Y_3adams}parent(adams, Z_3),ancestor(Z_3, adams).
An Example
?- ancestor(adams, adams).
σ5 = {X_3 adams,Y_3 adams}
σ5(parent(X_3, Z_3), ancestor(Z_3, Y_3))
= parent(adams, Z_3), ancestor(Z_3, adams)
?- parent(adams, Z_3), ancestor(Z_3, adams).
(fail)
parent(adams, Z_3), ancestor(Z_3, adams).
false false
An Example
?- parent(X_1, Z_1), ancestor(Z_1, adams).
σ2 = {X_1 derek, Z_1 adams}
σ2(ancestor(Z_1, adams)) = ancestor(adams, adams)
?- ancestor(adams, adams).
σ3 = {X_2 adams, Y_2 adams}
σ3(parent(X_2, Y_2)) = parent(adams, adams)
?- parent(adams, adams). (fail)
An Example
ancestor(adams, adams).
σ3 = {X_2 adams,Y_2 adams} σ3 = {X_2 adams,Y_2 adams}
parent (adams, adams).
falsefalse
parent(adams, Z_1), ancestor(Z_1, adams)).
falsefalse
An Example
?- ancestor(adams, adams).
σ3 = {X_2 adams, Y_2 adams}
σ3(parent(X_2, Z_2), ancestor(Z_2, Y_2)) = parent(adams, Z_2), ancestor(Z_2, adams)
?- parent(adams, Z_1), ancestor(Z_1, adams).
(fail)
Prolog Search Tree ancestor(X,adams) σ1 = {X→X_1,Y_1→adams}
parent(X_1,adams) parent(X_1,Z_1),ancestor(Z_1,adams) σ2 = {X_1→derek} σ2 = {X_1ted,Z_1derek} σ2 = {X_1derek,Z_1adams}
fail succeed ancestor(derek,adams) ancestor(adams,adams) X = derek σ3 = {X_2derek,Y_2adams}
parent(derek,adams) parent(derek,Z_2),ancestor(Z_2,adams) fail fail σ4 = { } σ4 = {Z_2 adams}
fail succeed fail ancestor(adams, adams) X = ted σ5 = {X_3adams,Y_3adams}
parent(adams,adams) parent(adams,Z_3),ancestor(Z_3,adams)
fail fail fail fail
Literal Order Affects Treesappend([ ], L, L).append([H|X ], Y, [ H|Z ]) :- append (X, Y, Z).prefix(X, Z) :- append (X, Y, Z).suffix (Y, Z) :- append (X, Y, Z).
?-suffix( [a], L), prefix (L, [a, b, c]).L = [a];-- non-terminating –
?-suffix ([a], L).L = [a];L = [_1, a];L = [_1, _2, a];…
Literal Order Affects Treessuffix ([a], L), prefix (L, [a, b, c])
append(X_1, [a], L), prefix (L, [a, b, c])
prefix([a], [a,b,c]) append(X_2, [a], Z_2), prefix([H_2|Z_2], [a, b, c])
append([a], Y_2, [a, b, c]) prefix([H_2|[a]], [a, b, c]) fail …
fail append([ ], Y_3, [b, c]) append([H_2|[a]], Y_3, [a, b, c])
succeed fail fail fail
Literal Order Affects Trees
suffix ([a], L), prefix (L, [a, b, c])
L = [a]
prefix([a], [a, b, c])
L = [_1,a]
prefix([_1,a], [a, b, c])
L = [_1,_2,a]
prefix([_1,_2,a], [a, b, c])
...
succeed
fail
fail
Literal Order Affects Trees
append([ ], L, L).append([H|X ], Y, [ H|Z ]) :- append (X, Y, Z).
prefix(X, Z) :- append (X, Y, Z).suffix (Y, Z) :- append (X, Y, Z).
?- prefix(L, [a, b, c]), suffix ([a], L).L = [a];no
Literal Order Affects Trees
prefix (L, [a, b, c]), suffix ([a], L)
append (L, Y_1, [a, b, c]), suffix ([a], L)
suffix([a], [ ]) append(X_2, Y_2, [b, c]), suffix ([a], [a|X_2])
append(X_3, [a], []) suffix([a], [a]) append(X_3, Y_3, [c]),
suffix ([a], [a,b|X_3])
fail fail append(X_4, [a], [a])
succeed fail fail …
Literal Order Affects Trees
prefix (L, [a, b, c]), suffix ([a], L)
L = [ ]
suffix([a], [ ])L = [a]
suffix([a], [a])
L = [a,b]
suffix ([a], [a,b])
succeed
fail
fail L = [a,b,c]
suffix ([a], [a,b,c])
fail
Clause Order Affects Searchappend([ ], L, L).append([H|X], Y, [H|Z]) :- append(X, Y, Z).append2([H|X], Y, [H|Z]) :- append2(X, Y, Z).append2([ ], L, L).
?- append(X, [a], Z).X = [ ], Z = [a];X = [_1 ], Z = [_1, a];X = [_1, _2 ], Z = [_1, _2, a];…
?- append2(X, [a], Z).-- non-terminating --
Clause Order Affects Search
append(X, [c], Z) append2(X, [c], Z)
succeed succeed append(X_1, [c], Z_1) append2(X_1, [c], Z_1)
succeed succeed append (X_2, [c], Z_2) append2(X_2, [c], Z_2)
Terms as DataFunction symbols (functors) represent data
Lists: []
[a, b, c] .(a, .(b, .(c, [] ))) .(H , T) [H | T] [a | [b, c ]] [a, b | [c]] [a, b, c | [] ]
Trees:leafnonleaf(leaf, leaf)nonleaf(leaf, nonleaf(leaf, leaf ))
An Exampleappend([ ], L, L).append([H|X], Y, [H|Z]) :- append (X, Y, Z).?- append([ ], [ ], R).R = [ ];no ?- append([ ], [a, b], R) .R = [a, b];no?- append ([a, b], [c, d], R).R = [a, b, c, d];no ?- append (X, Y, [a, b] ).X = [ ], Y = [a, b];X = [a], Y = [b];X = [a, b], Y = [ ];no
The Predicate ‘functor’
?- functor(f(a, b, g(Z)), F, N).
Z = _23, F = f, N = 3
?- functor(a+b, F, N).F = +, N = 2
?- functor([a, b, c], F, N).F = . , N = 2
?- functor(apple, F, N).F = apple, N = 0
?- functor([a, b, c], ’.’, 3).no
?- functor(X, F, 2).X = f(_23, _24)
The Predicate ‘arg’• The predicate arg must be used with its first two
arguments instantiated
?- arg(2, related(john, mother(jane)), X) .X = mother(jane)
?- arg(1, a+(b+c), X) .X = a
?- arg(2, [a, b, c], X) .X = [b, c]
?- arg(1, a+(b+c), b) .no
An Examplesubterm(Term, Term).subterm(Sub, Term) :-
not atomic(Term),functor(Term, F, N),subterm(N, Sub, Term).
subterm(N, Sub, Term) :-N > 1,N1 is N-1,subterm(N1, Sub, Term).
subterm(N, Sub, Term) :-arg(N, Term, Arg).subterm(Sub, Arg).
The Predicate ‘=..’
?- foo(a, b, c) =.. X.X = [foo, a, b, c]
?- [a, b, c] =.. L.L = [’.’, a, [b, c]]
?- (a+b) =.. L.L = [+, a, b]
?- (a+b) =.. [+, X, Y]X = a, Y=b
?- X =.. [a, b, c]X = a(b,c)
An Example
subterm(Term, Term).subterm(Sub, Term) :- not atomic(Term),
Term =.. [F|Args],subterm_list(Sub, Args) .
subterm_list(Sub, [Arg|Args]) :- subterm(Sub, Arg).subterm_list(Sub, [Arg|Args]) :- subterm_list(Sub, Args).
Type Predicates
?- var(X) .yes
?- nonvar(X) .no
?- integer(23) .yes
?- atom(apple) .yes
?- atom(23) .no
?- atomic(apple) .yes
?- atomic(23)yes
The Predicate ‘=’
?- X = X.true;no
?- X = f(a).X = f(a);no
?- f(x) = f(a).X = a;no
?- f(X, b) = f(a, Y) .X = a, Y = b;no
?- f(X, b) = g(a, Y) .no
The Predicate ‘is’
?- X = 2 + 3.X = 2 + 3
?- X is 2 + 3.X = 5
?- X is 2 + 3, X = 5.X = 5
?- X is 2 + 3, X = 2 + 3.no
Relation Operators
?- 2 =:= 3.no
?- 2 =\= 3.yes
?- 2 > 3.no
?- 2 >= 3.no
?- 2 < 3.yes
?- 2 =< 3.yes
• A cut prunes the unexplored part of a Prolog search tree that is created during the execution of the predicate containing the cut.
H1 :- …
… Hi-1 :- …
Hi :- L1,…,Lj,!,Lj+1,…,Lm
Hi+1 :- …
…
Hn :- …
Cut(!)
Cut(!)H
H1 ... Hi-1 Hi+1 ... HnL1... Lj, !, Lj+1 ... Lm
L2... Lj, !, Lj+1 ... Lm
Lj, !, Lj+1 ... Lm
!, Lj+1 ... Lm
Lj+1 ... Lm
An Exampleqsort([], []).qsort([First|L], R) :- part(First, L, Ls, Lg), qsort(Ls, Rs), qsort(Lg, Rg), append(Rs, [First|Rg], R).
part(F, [], [], []).part(F, [X|L], [X|R1], R2) :- X =< F, !, part(F, L, R1, R2).part(F, [X|L], R1, [X|R2]) :- X > F, part(F, L, R1, R2).
Accumulator
qsort(Xs, Ys) :- qsort_tr(Xs, [], Ys).
qsort_tr([], Xs, Xs).
qsort_tr([X|Xs], Ys, Zs) :-
part(X, Xs, S, L),
qsort_tr(L, Ys, Ys1),
qsort_tr(S, [X|Ys1], Zs).
An Exampleperm([], []).perm(L, [R|Rs]) :- select(R, L, Ls), perm(Ls, Rs).select(X, [X|Xs], Xs).select(X, [Y|Ys], [Y|Zs]) :- select(X, Ys, Zs).
?- perm([a, b], R).R = [a, b];R = [b, a];no
?- select(R, [a, b], Ls) .R = a, Ls = [b];R = b, Ls = [a];no
Negation
• Logical negation: I can prove that it is false.
• First-order predicate calculus is undecidable: proving something true can always terminate, but proving something false may be non-terminating.
• Negation as failure: If I cannot prove that it is true, it must be false.
The Operator ‘not’
unmarried_student(X) :- student(X), not married(X).student(bill).married(joe).
?- unmarried_student(X).X = bill;no
The Implementation of ‘not’
not(X) :- X, !, fail.
not(_) .
Higher-Order Predicates
setof:
parent(ted, derek).parent(ted, dena).parent(derek, adams).
children(X, Kids) :- setof(C, parent(X,C), Kids).
?- children(ted, Kids).kids = [derek, dena];no
Higher-Order Predicatesbagof:
dept(ec, cs).dept(ec, ee).prof(cs, ted).prof(cs, derek).prof(ee, dena).prof(ee, ted).col_prof(C, P) :- dept(C, D), prof(D, P).col_profs(C, Ps) :- bagof(P, col_prof(C, P), Ps).
?- col_profs(ec, Ps).Ps = [ted, derek, dana, ted];no
Incomplete Data Structures
• The difference between two lists As and Bs can be denoted as a structure As\Bs, called a difference list.
• For example, [1, 2, 3|Xs]\Xs is the most general difference list representing the sequence 1, 2, 3, where [1, 2, 3|Xs] is the head and Xs the tail of the difference list.
Incomplete Data Structures
• Difference lists can lead to more concise and efficient programs.
• Two incomplete difference lists can be concatenated to give a third difference list in constant time. append_dl(Xs\Ys, Ys\Zs, Xs\Zs). ?- append_dl([a,b,c|Xs]\Xs,[1,2]\[],Ys). Xs = [1,2], Ys = [a,b,c,1,2]\[]
Difference Lists
qsort(Xs, Ys) :- qsort_dl(Xs, Ys\[ ]).qsort_dl([ ], Xs\Xs).qsort_dl([X|Xs], Ys\Zs) :-part(X, Xs, S, L),qsort_dl(S, Ys\[X|Ys1]), qsort_dl(L, Ys1\Zs).
qsort(Xs, Ys) :- qsort_dl(Xs, Ys, [ ]).qsort_dl([ ], Xs, Xs).qsort_dl([X|Xs], Ys, Zs) :-part(X, Xs, S, L),qsort_dl(S, Ys, [X|Ys1]), qsort_dl(L, Ys1, Zs).
Difference Listsqsort([5,7,3], Ys) qsort_dl([5,7,3], Ys\[ ]) part(5, [7,3], S1, L1) S1 = [3], L1 = [7] qsort_dl([3], Ys\[5|Ys1]) part(3, [ ], S2, L2) S2 = [ ], L2 = [ ] qsort_dl([ ], Ys\[3|Ys2]) Ys = [3|Ys2] qsort_dl([ ], Ys2\[5|Ys1]) Ys2 = [5|Ys1] qsort_dl([7], Ys1\[ ]) part(7, [ ], S3, L3) S3 = [ ], L3 = [ ] qsort_dl([ ], Ys1\[7|Ys3]) Ys1 = [7|Ys3] qsort_dl([ ], Ys3\[ ]) Ys3 = [ ]
Ys = [3,5,7]
Dictionaries
lookup(Key, [(Key,Value)|Dict], Value).lookup(Key,[(Key1,Value1)|Dict], Value) :-
Key =\= Key1, lookup(Key, Dict, Value).
Dict = [(ted,3301),(derek,3302)|Xs] ?- lookup(derek, Dict, N).
N = 3302 ?- lookup(dena, Dict, 3303). Dict = [(ted,3301),(derek,3302),(dena,3303)|Xs1]
Summary
• Logic programming uses logic as a
programming language and is declarative.
• Logic programming computes relations
instead of functions.
• Logic programming uses unification to
achieve bidirectional parameter passing
and to make use of incomplete data
structures.