Implementing prolog
Download
1 / 37

Implementing Prolog - PowerPoint PPT Presentation


  • 279 Views
  • Updated On :

Implementing Prolog. Outline. Parts of Chapter 20, with implementation 20.2 Unification 20.4 Implementing Prolog From 20.5: Variable renaming. Substitutions. A substitution is a function that maps variables to terms:  = { X  a , Y  f(a,b) }

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Implementing Prolog' - tarika


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
Implementing prolog l.jpg

Implementing Prolog

Modern Programming Languages


Outline l.jpg
Outline

  • Parts of Chapter 20, with implementation

    • 20.2 Unification

    • 20.4 Implementing Prolog

    • From 20.5: Variable renaming

Modern Programming Languages


Substitutions l.jpg
Substitutions

  • A substitution is a function that maps variables to terms: = {Xa, Yf(a,b)}

  • This  maps X to a and Y to f(a,b)

  • The result of applying a substitution to a term is an instance of the term

  • (g(X,Y)) = g(a,f(a,b)) so g(a,f(a,b)) is an instance of g(X,Y)

Modern Programming Languages


Unification l.jpg
Unification

  • Two Prolog terms t1 and t2unify if there is some substitution  (their unifier) that makes them identical: (t1) = (t2)

    • a and b do not unify

    • f(X,b) and f(a,Y) unify: a unifier is {Xa, Yb}

    • f(X,b) and g(X,b) do not unify

    • a(X,X,b) and a(b,X,X) unify: a unifier is {Xb}

    • a(X,X,b) and a(c,X,X) do not unify

    • a(X,f) and a(X,f) do unify: a unifier is {}

Modern Programming Languages


Multiple unifiers l.jpg
Multiple Unifiers

  • parent(X,Y) and parent(fred,Y):

    • one unifier is 1 = {Xfred}

    • another is 2 ={Xfred, Ymary}

  • Prolog chooses unifiers like 1 that do just enough substitution to unify, and no more

  • That is, it chooses the MGU—the Most General Unifier

Modern Programming Languages


Slide6 l.jpg
MGU

  • Term x1 is more general than x2 if x2 is an instance of x1 but x1 is not an instance of x2

    • Example: parent(fred,Y) is more general than parent(fred,mary)

  • A unifier 1 of two terms t1 and t2 is an MGU if there is no other unifier 2 such that 2(t1) is more general than 1(t1)

  • MGU is unique up to variable renaming

Modern Programming Languages


Unification for everything l.jpg
Unification For Everything

  • Parameter passing

    • reverse([1,2,3],X)

  • Binding

    • X=0

  • Data construction

    • X=.(1,[2,3])

  • Data selection

    • [1,2,3]=.(X,Y)

Modern Programming Languages


The occurs check l.jpg
The Occurs Check

  • Any variable X and term t unify with {Xt}:

    • X and b unify: an MGU is {Xb}

    • X and f(a,g(b,c)) unify: an MGU is {Xf(a,g(b,c))}

    • X and f(a,Y) unify: an MGU is {Xf(a,Y)}

  • Unless X occurs in t:

    • X and f(a,X)do not unify, in particular not by {Xf(a,X)}

Modern Programming Languages


Occurs check example l.jpg
Occurs Check Example

append([], B, B).append([Head|TailA], B, [Head|TailC]) :- append(TailA, B, TailC).

  • Most Prologs omit the occurs check

  • ISO standard says the result of Prolog “unification” is undefined in cases that should fail the occurs check

?- append([], X, [a | X]).X = [a, a, a, a, a, a, a, a, a|...] Yes

Modern Programming Languages


Ml implementation l.jpg
ML Implementation

  • We will look at an implementation of Prolog in ML

  • First, some code for representing terms

Modern Programming Languages


Representing terms l.jpg
Representing Terms

(*

A datatype for Prolog terms. A term can be an

Atom, a Variable, or a Compound term. We

represent all the lexemes using strings.

*)

datatype term =

Atom of string |

Variable of string |

Compound of string * term list;

Modern Programming Languages


Example prolog clause l.jpg
Example Prolog Clause

(* p(f(Y)) :- q(Y),r(Y). *)

val c1 = [Compound("p",[Compound("f",[Variable("Y")])]),

Compound("q",[Variable("Y")]),

Compound("r",[Variable("Y")])];

Modern Programming Languages


Substitution l.jpg
Substitution

(*

A special mapping function for terms. We convert a term into the

new term formed by applying the function f to all the variables

(but leaving all the atoms and predicate names unaltered). *)

fun mapVariable f (Atom x) = Atom(x)

| mapVariable f (Variable n) = f n

| mapVariable f (Compound(n, terms)) =

Compound(n, map (mapVariable f) terms);

(*

Create a substitution. We take a variable name and a term, and

return a function that can be used to apply that substitution to

any term.

*)

fun sub name term =

mapVariable (fn n => if n=name then term else Variable n);

Modern Programming Languages


Unification14 l.jpg
Unification

(*

Find a most general unifier of two terms. We return a pair of

values, like this:

val (unifiable, unifier) = mgu(a,b)

The first value we return is a boolean, true iff the two terms

are unifiable. If they are, the second value we return is a

most general unifier: a function that, when applied to a and b,

makes them identical. We do not perform the occurs check.

*)

fun mgu(a,b) =

let fun ut([], [], unifier) =

(true, unifier)

| ut(term::t1, Variable(name)::t2, unifier) =

let val r = (sub name term) o unifier in

ut(map r t1, map r t2, r)

end

| ut(Variable(name)::t1, term::t2, unifier) =

let val r = (sub name term) o unifier in

ut(map r t1, map r t2, r)

end

Modern Programming Languages


More unification l.jpg
More Unification

| ut(Atom(n)::t1, Atom(m)::t2, unifier) =

if n=m then ut(t1,t2,unifier) else (false, unifier)

| ut(Compound(n1,xt1)::t1, Compound(n2,xt2)::t2, unifier) =

if n1=n2 andalso length xt1 = length xt2 then ut([email protected], [email protected], unifier)

else (false, unifier)

| ut(_,_,unifier) = (false, unifier);

in

ut([a],[b], (fn x => x))

end;

Modern Programming Languages


About unification algorithms l.jpg
About Unification Algorithms

  • The one just shown takes exponential time in the worst case

  • In fact, any algorithm that linearly represents the unified term, without shared structure, takes exponential time and space

  • Using fancier techniques, it can be done in linear time

Modern Programming Languages


Outline17 l.jpg
Outline

  • Parts of Chapter 20, with implementation

    • 20.2 Unification

    • 20.4 Implementing Prolog

    • From 20.5: Variable renaming

Modern Programming Languages


Resolution l.jpg
Resolution

  • The hardwired inference step

  • A clause is represented as a list of terms (a list of one term, if it is a fact)

  • Resolution step applies one clause, once, to make progress on a list of goal terms

function resolution(clause, goals):let sub = the MGU of head(clause) and head(goals)return sub(tail(clause) concatenated with tail(goals))

Modern Programming Languages


Resolution example l.jpg
Resolution Example

Given this list of goal terms:[p(X),s(X)]And this rule to apply:p(f(Y)) :- q(Y), r(Y).The MGU of the heads is {Xf(Y)}, and we get:resolution([p(f(Y)),q(Y),r(Y)], [p(X),s(X)]) = [q(Y),r(Y),s(f(Y))]

function resolution(clause, goals):let sub = the MGU of head(clause) and head(goals)return sub(tail(clause) concatenated with tail(goals))

Modern Programming Languages


Resolution in ml l.jpg
Resolution in ML

fun resolution(head::conds,goal::goals) =

let

val (unifiable, unifier) = mgu(head,goal)

in

map unifier ([email protected])

end;

function resolution(clause, goals):let sub = the MGU of head(clause) and head(goals)return sub(tail(clause) concatenated with tail(goals))

Modern Programming Languages


A prolog interpreter l.jpg
A Prolog Interpreter

function solve(goals)if goals is empty then succeed()else for each clause c in the program, in orderif head(c) does not unify with head(goals) then do nothingelse solve(resolution(c, goals))

Modern Programming Languages


Slide22 l.jpg

Program:

1. p(f(Y)) :- q(Y),r(Y).2. q(g(Z)).3. q(h(Z)).4. r(h(a)).

A partial trace for query p(X):

solve([p(X)]) 1. solve([q(Y),r(Y)]) … 2. nothing 3. nothing 4. nothing

  • solve tries each of the four clauses in turn

    • The first works, so it calls itself recursively on the result of the resolution step (not shown yet)

    • The other three do not work: heads do not unify with the first goal term

Modern Programming Languages


Slide23 l.jpg

Program:

1. p(f(Y)) :- q(Y),r(Y).2. q(g(Z)).3. q(h(Z)).4. r(h(a)).

A partial trace for query p(X), expanded:

solve([p(X)]) 1. solve([q(Y),r(Y)])1.nothing2. solve([r(g(Z))]) …3. solve([r(h(Z))]) …4.nothing2.nothing3.nothing4.nothing

Modern Programming Languages


Slide24 l.jpg

Program:

1. p(f(Y)) :- q(Y),r(Y).2. q(g(Z)).3. q(h(Z)).4. r(h(a)).

A complete trace for query p(X):

solve([p(X)]) 1. solve([q(Y),r(Y)]) 1.nothing2. solve([r(g(Z))]) 1.nothing2.nothing3.nothing4.nothing3. solve([r(h(Z))]) 1.nothing2.nothing3.nothing4. solve([]) —success!4.nothing2.nothing3.nothing4.nothing

Modern Programming Languages


Collecting the substitutions l.jpg
Collecting The Substitutions

function resolution(clause, goals, query):let sub = the MGU of head(clause) and head(goals)return (sub(tail(clause) concatenated with tail(goals)), sub(query))

function solve(goals, query)if goals is empty then succeed(query)else for each clause c in the program, in orderif head(c) does not unify with head(goals) then do nothingelse solve(resolution(c, goals, query))

  • Modified to pass original query along and apply all substitutions to it

  • Proved instance is passed to succeed

Modern Programming Languages


Slide26 l.jpg

Program:

1. p(f(Y)) :- q(Y),r(Y).2. q(g(Z)).3. q(h(Z)).4. r(h(a)).

A complete trace for query p(X):

solve([p(X)],p(X)) 1. solve([q(Y),r(Y)],p(f(Y))) 1.nothing2. solve([r(g(Z))],p(f(g(Z)))) 1.nothing2.nothing3.nothing4.nothing3. solve([r(h(Z))],p(f(h(Z)))) 1.nothing2.nothing3.nothing4. solve([],p(f(h(Z))))4.nothing2.nothing3.nothing4.nothing

Modern Programming Languages


Prolog in ml l.jpg
Prolog in ML

fun solve(_,nil,query) = succeed query

| solve(program,goal::goals,query) =

let fun onestep (head::conds, _) =

let

val (unifiable, unifier) = mgu(head,goal)

in

if unifiable

then solve(program, map unifier ([email protected]), unifier query)

else true

end

in

foldl onestep true program

end;

fun prolog(program,query) = solve(program,[query],query);

Modern Programming Languages


Outline28 l.jpg
Outline

  • Parts of Chapter 20, with implementation

    • 20.2 Unification

    • 20.4 Implementing Prolog

    • From 20.5: Variable renaming

Modern Programming Languages


A problem l.jpg
A Problem

  • Model of Prolog execution just shown is flawed, as is the ML Prolog implementation

  • It works on some examples

  • On others it does not agree with common sense, or with the actual behavior of a Prolog language system

  • For instance, reverse([1,2],X)

Modern Programming Languages


Slide30 l.jpg

Program:

1. reverse([],[]).2. reverse([Head|Tail],X) :- reverse(Tail,Y), append(Y,[Head],X).

A trace for query reverse([1,2],X)

solve([reverse([1,2],X)]) 1. nothing 2. solve([reverse([2],Y),append(Y,[1],X)]) 1.nothing2. solve([reverse([],X), append(X,[2],X), append(X,[1],X)]) 1.solve([append([],[2],[]), append([],[1],[])])…no solution: what went wrong?2.nothing

Modern Programming Languages


Slide31 l.jpg

Program:

1. reverse([],[]).2. reverse([Head|Tail],X) :- reverse(Tail,Y), append(Y,[Head],X).

This step was wrong; we substituted X for Y, but there is already an X in the goal list

A trace for query reverse([1,2],X)

solve([reverse([1,2],X)]) 1. nothing 2. solve([reverse([2],Y),append(Y,[1],X)]) 1.nothing2. solve([reverse([],X), append(X,[2],X), append(X,[1],X)]) 1.solve([append([],[2],[]), append([],[1],[])])…no solution2.nothing

Modern Programming Languages


Capture l.jpg
Capture

  • Recall Prolog’s scope rule: the scope of a definition of a variable is the clause containing it

  • Our resolution step mashes two scopes together, incorrectly identifying any variables that happen to have the same names

  • Another kind of capture

Modern Programming Languages


Variable renaming l.jpg
Variable Renaming

  • To avoid capture, use fresh variable names for each clause, every time you apply it

  • The first application of reverse might be:

  • And the next might be:

  • And so on…

reverse([Head1|Tail1],X1) :- reverse(Tail1,Y1), append(Y1,[Head1],X1).

reverse([Head2|Tail2],X2) :- reverse(Tail2,Y2), append(Y2,[Head2],X2).

Modern Programming Languages


Slide34 l.jpg

Program:

1. reverse([],[]).2. reverse([Head|Tail],X) :- reverse(Tail,Y), append(Y,[Head],X).

A trace for query reverse([1,2],X)

solve([reverse([1,2],X)]) 1. nothing 2. solve([reverse([2],Y1),append(Y1,[1],X1)]) 1.nothing2. solve([reverse([],Y2), append(Y2,[2],X2), append(X2,[1],X1)]) 1.solve([append([],[2],X2), append(X2,[1],X1)])…solution with X2=[2], X1=[2,1] 2.nothing

Modern Programming Languages


Ml renaming l.jpg
ML Renaming

  • This ML implementation solves the problem by renaming

  • It adds “#n” to the end of every variable name whenever a clause from the program is used, where n is the depth of the recursion

  • Real Prologs find a more efficient way to do this, of course

Modern Programming Languages


Slide36 l.jpg

fun rename iter term = mapVariable (fn n => Variable(n^"#"^iter)) term;

fun solve(_,nil,query,_) = succeed query

| solve(program,goal::goals,query,depth) =

let fun onestep (clause, _) =

let

val head::conds =

map (rename (Int.toString depth)) clause

val (unifiable, unifier) = mgu(head,goal)

in

if unifiable

then solve(program, map unifier ([email protected]), unifier query, depth+1)

else true

end

in

foldl onestep true program

end;

fun prolog(program,query) = solve(program,[query],query,1);

Modern Programming Languages


Conclusion l.jpg
Conclusion

  • Prolog has a simple model of execution

    • Compare with implementations of similar interpreters for Java or ML

    • (We’ll use Prolog to write some interpreters for ML-like languages in Chapter 23)

    • Interestingly: using Prolog is tricky, in spite of its simple interpreter and simple syntax

  • ML is a good language for this kind of thing

Modern Programming Languages


ad