🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.prolog
Article #317

A phrase generator for Prolog DCG's

#317
From: Ken Johnson
Date: Tue, 12 Sep 1989 16:54
132 lines
5299 bytes
I've found that the usual way of teaching about grammars with Lisp and
Logo involves generating random phrases freom a grammar whereas Prolog's
DCG mechanism does not allow you to do that: it just checks whether a
given string of non-terminals can be derived from the grammar or not. 

Here is a phrase generator that generates phrases at random from a DCG,
which may add a touch of humour to an otherwise forebodingly dull topic. 
(That's a value judgement of course and you're free to disagree with
it.) There is a simple DCG attached to this phrase generator; it should
work with other DCGs.  If anyone can find a general way to make the code
understand about arguments to non-terminals, I would be interested to
see how it is done.  (I mean rules like sentence(Number) -->
nounphrase(Number), verbphrase(Number).  where Number is `singular' or
`plural'). 

*************************************************************************
*	H. M. GOVERNMENT HEALTH WARNING...				*
*                                                                       *
*	The code ASSUMES that your Prolog stores DCG information	*
*	in the same way that Edinburgh Prolog does.  Not all		*
*	Prologs store DCG rules that way. 				*
*************************************************************************

I have tested this code with Edinburgh Prolog (the New Implementation),
version 1.5.04 dated 12 September 1988 (Happy birthday to you, happy
birthday to yooooooooooooooo! :-) and it seemed to work. 

To run the program as it stands, give the command

	?- repeat,
		gen_phrase(insult,Stuff),
		write(Stuff),
		nl,
		fail.

Share, enjoy, and good luck:

Cut here ------------ 8< ------------ cut here ------------ 8< ------------
% Phrase generator: generate a phrase at random from a simple DCG.
% Ken Johnson 12-9-89
% You may make and distribute copies of this code if you want to,
% except that if you sell them at a profit I want a share.

% The top level phrase generator: given a class name it will
% produce a sentence that matches the pattern defined in the DCG.
% Example invocation:
% gen_phrase(insult,Outcome).
% The insults grammar is given after the important bits.

% This generator does not understand about arguments to non-terminals,
% the use of { }, or anything else. Don't say I didn't tell you.

gen_phrase(Class,Outcome) :-			% This predicate serves only
	gen_1_phrase(Class,Outcome).		% to give repeated
						% instantiations of Outcome
gen_phrase(Class,Outcome) :-			% on backtracking.
	gen_phrase(Class,Outcome).

% Generate a single phrase

gen_1_phrase(Class,Outcome) :-
	gen_1_phrase(Class,X-X,Outcome-[]).	% Call with accumulator X-X

gen_1_phrase(Class,So_far,Outcome) :-		% Create a term insult(_,_)
	functor(Term,Class,2),			% which matches the clauses
	setof(Body,clause(Term,Body),Set),	% of the DCG, then pick one
	pick_one(Set,A_body),			% matching clause and
	expand(A_body,So_far,Outcome).		% expand it

% Expand a non-terminal, or sequence of non-terminals

expand((P,Q),A,C) :-				% Expand (P,Q) by expanding
	!,					% P and then appending the
	expand(P,A,B),				% expansion of Q
	expand(Q,B,C).

expand('C'(_,Word,_),U-[Word|V],U-V).		% The predicate `C' processes
						% ground atoms; for non-
expand(Term,So_far,Outcome) :-			% terminals, use gen_1_phrase
	functor(Term,Functor,_),		% recursively to expand them
	Functor \== 'C',
	gen_1_phrase(Functor,So_far,Outcome).

% Pick at random from a list

pick_one(List,Element) :-
	length(List,Length),
	random(Length,Random_int),
	nth(Random_int,List,Element).


nth(0,[X|_],X).					% n'th element of a list

nth(N,[_|T],X) :-
	N > 0,
	M is N - 1,
	nth(M,T,X).

random(Modulus,N) :-				% Pretty awful random number
	recorded(random_seed,Seed,Ref),		% generator. If no seed, it
	!,					% uses 13 so it always goes
	erase(Ref),				% through the same sequence
	random(Modulus,Seed,N).

random(Modulus,N) :-
	random(Modulus,13,N).

random(Modulus,Seed,N) :-
	New is ((125 * Seed) mod 4093),
	record(random_seed,New,_),
	N is New mod Modulus.

% ------------------------------------------------------------------------
% An Insults Grammar
% Here is an example DCG with which gen_phrase works
% I first came across this grammar in Alan Bundy's book so I think I
% ought tell you it isn't original to me.

insult --> action, [you], misname.

action --> [sod,off].
action --> [take,a,running,jump].

misname --> [cretin].
misname --> [bum].
misname --> [great,pillock].

-- 
Ken Johnson, AI Applications Institute, 80 South Bridge, Edinburgh EH1 1HN
E-mail ken@aiai.ed.ac.uk, phone 031-225 4464 extension 212
`I have read your article, Mr.  Johnson, and I am no wiser than when I
started.' -- `Possibly not, sir, but far better informed.'
Technical Details
Message-ID: <873@skye.ed.ac.uk>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!purdue!ames!lll-winken!uunet!mcsun!ukc!edcastle!aiai!ken

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!purdue!ames!lll-winken!uunet!mcsun!ukc!edcastle!aiai!ken
From: ken@aiai.ed.ac.uk (Ken Johnson)
Newsgroups: comp.lang.prolog
Subject: A phrase generator for Prolog DCG's
Keywords: dcg prolog sentences
Message-ID: <873@skye.ed.ac.uk>
Date: 12 Sep 89 16:54:10 GMT
Reply-To: ken@aiai.UUCP (Ken Johnson)
Followup-To: comp.lang.prolog
Organization: AIAI, University of Edinburgh, Scotland
Lines: 132