06-25433 – Logic Programming 06-25433 – Logic Programming

This lecture …

Writing DCGs is introduced showing: – the basic framework; Definite Clause Grammar – embedding calls to “ordinary” ; – building structures.

Context-Free Grammar (CFG) is DCGs suffer from problems with left-recursive rules. introduced as a way of writing rules about structured knowledge. Definite Clause DCGs are a general programming tool with Grammar (DCG) is Prolog’s in-built applications beyond language . notation for writing CFGs.

12 - Definite Clause Grammar 1

06-25433 – Logic Programming 06-25433 – Logic Programming What do we know about atoms, integers Type testing by scanning and variables? Imagine we have a Prolog term and want to decide if (For the time being), an atom begins with a it is: lowercase letter and can be followed by any upper or • integer (e.g. 1, 123, …) lowercase letter, digit or ‘_’: • atom (e.g. a, abc, aBC12) • Variable (e.g. Butter, _123) atom ::= lowercase other_symb

Also, assume we have a list of the terms as other_symb ::= lowercase other_symb | individual atoms, e.g. uppercase other_symb | [' 1 ', ' 2 ', ' 3 '] digit other_symb | [a, ' B ', ' C ', ' 1 ', ' 2 '] "" % i.e. nothing

12 - Definite Clause Grammar 2 12 - Definite Clause Grammar 3

06-25433 – Logic Programming 06-25433 – Logic Programming

Writing this in Prolog Writing this in Prolog term(atom) --> remaining_terms --> “;” is another way of lower_case, remaining_terms. ( lower_case ; expressing OR- upper_case ; choice. It is best used lower_case --> Code within { … } is under_score ; only when the options treated as “normal” are deterministic. [Letter], digit ), Prolog code. { Letter @>= 'a', remaining_terms. Letter @=< 'z' }. remaining_terms --> @>=, @>, @=< and []. … continued @< test term equality or precedence.

12 - Definite Clause Grammar 4 12 - Definite Clause Grammar 5

1 06-25433 – Logic Programming 06-25433 – Logic Programming

What does this mean? What does this mean? lower_case --> term(atom) --> [Letter], lower_case, remaining_terms. { Letter @>= 'a', Letter @=< 'z' }. is Prolog short-hand for writing: is Prolog short-hand for writing: term(atom, S0, S) :- lower_case([Letter|S], S) :- lower_case(S0, S1), Letter @>= 'a', remaining_terms(S1, S). Letter @=< 'z'.

12 - Definite Clause Grammar 6 12 - Definite Clause Grammar 7

06-25433 – Logic Programming 06-25433 – Logic Programming

What does this mean? What is Prolog doing? remaining_terms(S0, S) :- Meta-interpreting ( lower_case(S0, S1) ; This means writing code in one form and compiling upper_case(S0, S1) it (automatically) into another, runable, form. ; under_score(S0, S1) Meta-interpreting is usually used to allow domain ; experts to write knowledge in a user-friendly way digit(S0, S1) ), but compile it into machine-friendly code. remaining_terms(S1, S). This is similar to how we transformed formulas in remaining_terms(S, S). logic.

12 - Definite Clause Grammar 8 12 - Definite Clause Grammar 9

06-25433 – Logic Programming 06-25433 – Logic Programming Prolog’s in-built A first anatomy of DCGs - 1 grammar rule notation A rule is written: Definite Clause Grammar (DCG) is an in-built notation that looks like a CFG. left_hand --> right_side1, DCGs can be executed as Prolog programs. right_side2, dict_entry. This means that DCGs run exactly like Prolog: top- down and depth-first. We can write words directly into rules as follows:

(DCGs can also be used as a rule base to be used by left_hand --> another Prolog program – e.g. a .) right_side1, [noddy], right_side2.

12 - Definite Clause Grammar 10 12 - Definite Clause Grammar 11

2 06-25433 – Logic Programming 06-25433 – Logic Programming

A first anatomy of DCGs - 2 What a DCG is compiled into - 1

Dictionary entries are written as: Our rules become:

left_hand(S0, S) :- dict_entry --> [the]. right_side1(S0, S1), dict_entry --> [river,avon]. right_side2(S1, S2), dict_entry(S2, S).

left_hand(S0, S) :- right_side1(S0, S1), ‘C’(S1,noddy, S2) right_side2(S2, S).

12 - Definite Clause Grammar 12 12 - Definite Clause Grammar 13

06-25433 – Logic Programming 06-25433 – Logic Programming

What a DCG is compiled into - 2 Using DCG in a program checker

Dictionary entries become: One of the strengths of declarative languages such as Prolog and Haskell is the ease with which programs dict_entry(S0, S) :- can be written to manipulate other programs – or ‘C’(S0, the, S). themselves. and there is an in-built fact: This program checks that there are clauses for every subgoal in a program. ‘C’([Token|S], Token, S).

12 - Definite Clause Grammar 14 12 - Definite Clause Grammar 15

06-25433 – Logic Programming 06-25433 – Logic Programming

The general idea Design

Given a clause such as: At the highest level: read_text(Current_Word) :- 1. Open a file, read in a program to a list and close look_up(Current_Word), the file; read(Next_Word), read_text(Next_Word). 2. Parse each clause, listing goals (heads) and subgoals (from the bodies of rules); check there is a rule or fact for each subgoal (unless the subgoal is built-in, like read/1). 3. Check that each subgoal has a definition and report to the user.

12 - Definite Clause Grammar 16 12 - Definite Clause Grammar 17

3 06-25433 – Logic Programming 06-25433 – Logic Programming Open a file, read in a program to a list Parse each clause, listing goals (heads) and close the file and subgoals (from the bodies of rules) The code for this is on the WWW and described in This is easy using DCG: the notes. clause(Goals0, Goals, It is fairly straightforward for someone who knows Sub_Goals, Sub_Goals) --> how to open, read and close files in another [Fact], language. { % check this isn’t a rule The important point is the output is a list of clauses: Fact \= (_ :- _), [skills(fred,jones,C++), % extract the fact as a goal (happy_student(_6016):- add_goal(Fact, Goals0, Goals) module_reg(_6016,prolog))] }.

12 - Definite Clause Grammar 18 12 - Definite Clause Grammar 19

06-25433 – Logic Programming 06-25433 – Logic Programming Parse each clause, listing goals (heads) Processing bodies and subgoals (from the bodies of rules) This is easy using DCG: The body of a Prolog rule is a conjunction of terms: clause(Goals0, Goals, body(Sub_Goals0, Sub_Goals, Sub_Goals0, Sub_Goals) --> (Body, Bodies)) :- [(Head :- Body)], add_goal(Body, Sub_Goals0, { Sub_Goals1), % extract the head as a goal body(Sub_Goals1, Sub_Goals, Bodies). add_goal(Head, Goals0, Goals), % extract the subgoals body(Sub_Goals0, Sub_Goals, Body) :- body(Sub_Goals0, Sub_Goals, Body) Body \= (_,_), }. add_goal(Body, Sub_Goals0,

Sub_Goals). 12 - Definite Clause Grammar 20 12 - Definite Clause Grammar 21

06-25433 – Logic Programming 06-25433 – Logic Programming Check that each subgoal has a definition Parsing clauses and report to the user This follows a very common pattern in parsing with DCGs: For each subgoal, check that there is a corresponding goal in the Goal list. clauses(Goals0, Goals, Sub_Goals0, Sub_Goals) --> This is very similar to checking history lists. The main checking code is: clause(Goals0, Goals1,

Sub_Goals0, Sub_Goals1), % subgoal is not ins goal list clauses(Goals1, Goals, not_member(Goals, Sub_Goal/Arity), Sub_Goals1, Sub_Goals). % check subgoal is not a built-in clauses(Goals, Goals, functor(Predicate,S ub_Goal,Arity), Sub_Goals, Sub_Goals) --> []. \+ predicate_property(Predicate,built_in)

12 - Definite Clause Grammar 22 12 - Definite Clause Grammar 23

4 06-25433 – Logic Programming 06-25433 – Logic Programming The basic idea of The basic idea of Context-Free Grammar - 1 Context-Free Grammar - 2

A CFG has several parts: right-hand  symbol

right-hand  symbol grammar  rule right-hand grammar  rule grammar dictionary  entry

rule  left-hand dictionary  entry right-hand dictionary

left-hand  symbol

12 - Definite Clause Grammar 24 12 - Definite Clause Grammar 25

06-25433 – Logic Programming 06-25433 – Logic Programming

Context-Free Grammar (CFG) - 1 Context-Free Grammar (CFG) - 2

Context-free grammar is a formalism for writing and this is the lexicon: rules that describe things that are structured. determiner  the This is a grammar for a sentence: noun  cat We will use S  NP VP abbreviations in noun  mat NP  determiner noun our grammar: prep preposition  on and det. VP  verb PP verb  sat PP  preposition NP

12 - Definite Clause Grammar 26 12 - Definite Clause Grammar 27

06-25433 – Logic Programming 06-25433 – Logic Programming

Context-Free Grammar (CFG) - 3 A Definite Clause Grammar (DCG) - 1

Applying these rules we get: DCG allows us to write CFGs in Prolog that look S almost exactly like CFGs:

NP VP s --> np, vp. np --> det, noun. det noun verb PP vp --> verb, pp. pp --> prep, np.

the cat sat prep NP det --> [the]. noun --> [cat]. noun --> [mat]. prep --> [on]. on det noun verb --> [sat].

the mat

12 - Definite Clause Grammar 28 12 - Definite Clause Grammar 29

5 06-25433 – Logic Programming 06-25433 – Logic Programming Problems with Prolog’s Definite Clause Grammar (DCG) - 2 depth-first search

We can add extra arguments to DCGs - e.g. to make As with all Prolog programs, left-recursive rules will give a [syntax] phrase structure tree: problems: s(s(NP, VP)) --> np(NP), vp(VP). % left recursive np(np(Det, Noun)) --> det(Det), np(np(NP1, NP2)) --> noun(Noun). np(NP1), noun(NP2). etc. np(np(Det)) --> det(det(the)) --> [the]. det(Det). noun(noun(cat)) --> [cat]. det(det(the)) --> [the]. etc. Demo 2 noun(noun(car)) --> [car].

12 - Definite Clause Grammar 30 12 - Definite Clause Grammar 31

06-25433 – Logic Programming 06-25433 – Logic Programming

Working around left-recursive rules - 1 Working around left-recursive rules - 2

As with all Prolog programs, left-recursive rules will give Method 2 problems: – Keep a list of points in the parsing – Examine the list to ensure that you’re not repeating a Method 1 - remove left-recursive rule by renaming: point. np(np(NP1, NP2)) --> np1(NP1), np(np(NP1,NP2),History0,History,S0,S) :- noun(NP2). \+ memb(entry(np, S0), History0), np(NP1, [entry(np, S0)|History0], np1(np(Det)) --> det(Det). History1, S0, S1), det(det(the)) --> [the]. noun(NP2, [entry(noun,S1)|History1], noun(noun(car)) --> [car]. History, S1, S).

12 - Definite Clause Grammar 32 12 - Definite Clause Grammar 33

06-25433 – Logic Programming 06-25433 – Logic Programming

Working around left-recursive rules - 3 Summary

Method 2 (continued) DCGs are a powerful and convenient implementation of CFG in Prolog. np(np(Det), History0, History) --> They allow rules which specify det(Det, History0, History). – structure building – arbitrary embedded Prolog code

Because DCGs use Prolog’s depth-first search, they have problems with left-recursive rules – but this can be eliminated.

DCGs are more than a language parsing tool – they have uses in a wide variety of programs.

12 - Definite Clause Grammar 34 12 - Definite Clause Grammar 35

6