Voting

Category

real language

Bookmarking

Del.icio.us Digg Diigo DZone Earthlink Google Kick.ie
Windows Live LookLater Ma.gnolia Reddit Rojo StumbleUpon Technorati

Language NU-Prolog

Date:05/22/05
Author:Lee Naish
URL:n/a
Comments:1
Info:http://www.cs.mu.oz.au/~lee/src/nuprolog/
Score: (3.02 in 132 votes)
% Beer song, see http://www.99-bottles-of-beer.net/
% (was http://www.ionet.net/~timtroyr/funhouse/beer.html)
% NU-Prolog (http://www.cs.mu.oz.au/~lee/src/nuprolog/) DCG version
% Author: Lee Naish lee@cs.mu.oz.au 4/2000
%
% DCG = Definite Clause Grammar, a grammar formalism supported by Prolog
% This version owes something to the Mercury version.
%
% Grammars are most commonly used for parsing strings but can also be
% used in reverse for generating strings.  In this case we need to
% parse/generate numbers which is a bit tricky in standard Prolog.
% However, NU-Prolog supports some reversible builtin predicates such as
% plus/3 and divides/4 and has "coroutining" (dynamic reordering of the
% calls based on data flow), allowing us to write simple elegant code
% which can parse the beer song and also generate it!
% beer(99, Song, []) binds Song to the text of the song.
% beer(99, Song, Song) binds Song to an infinite (circular) repetition
% of the text of the song (the occurs check is violated in the
% unification).

% top level goal for 99 bottles
main(_) :-
	beer(99, Song, []),
	format("~s", [Song]).

% First we declare b_o_b (short for bottles of beer) as a prefix operator
% to allow "N b_o_b" instead of "b_o_b(N)" for extra cuteness
:- op(10, xf, b_o_b).

% beer song - N is initial number of bottles
% (maximum 99 - we don't want to encourage drinking to excess!)
beer(N) --> {N > 0},
	N b_o_b, " on the wall,\n",
	N b_o_b, ".\n",
	"Take one down, pass it around,\n",
	{plus(N1, 1, N)}, N1 b_o_b, " on the wall.\n\n",
	beer(N1).
beer(0) --> "Go to the store and buy some more!\n".

% "N bottles of beer" (special cases for N=0 or 1)
0 b_o_b --> "No more bottles of beer".
1 b_o_b --> "1 bottle of beer".
N b_o_b --> {N > 1}, num(N), " bottles of beer".

% number in range 0-99 - N = numeric value
num(N) --> digit(N).
num(N) --> digit(D0), digit(D),
	{D0 > 0, divides(N, 10, D0, D)}.
	
% single digit - N = numeric value
digit(N) --> [A],
	{0'0 =< A, A =< 0'9, plus(N, 0'0, A)}.

Download Source | Write Comment

Alternative Versions

Comments

>>  UMa said on 08/15/07 23:56:58

UMa % In SWI Prolog one has to define 'divide' properly and order the checks first (i.e. no automatic reordering):

num(N) -->
{N < 10, N >= 0},
digit(N).
num(N) -->
{divides(N, 10, D0, D)},
digit(D0),
digit(D).

divides(Num, Num1, Div, Rest) :-
Div is Num // Num1,
Rest is Num mod Num1.

% single digit - N = numeric value
digit(N) -->
{plus(N, 0'0, A)},
[A].

Download Source | Write Comment

Add Comment

Please provide a value for the fields Name, Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.

Please don't post large portions of code here! Use the form to submit new examples or updates instead!

Name:

eMail:

URL:

Security Code:
  
Comment: