🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.prolog
Article #2731

Prolog riddle summary - (nf)

#2731
From: noekel
Date: Tue, 28 Jul 1987 14:26
64 lines
3282 bytes
Thanks to everyone who cared to mail or post responses to my prolog riddle.
Although I have been told that I had duplicated the Goode Olde Prolog Riddle
known since the Dark Ages or so the answers have been surprisingly controversal.
This is a brief summary. 

The problem was to construct a Prolog program that

(1) *generates* natural numbers in ascending order,
(2) does not make use of side effects (assert, retract etc.),
(3) generates the first n numbers in time O(n).

The obvious solution to (1) and (2) is, of course,

	nat(0).
	nat(X) :- nat(Y), X is Y+1.

which unfortunately runs in O(N**2).

A number of people were convinced that this is the best one can manage
given the restrictions in (2). Some sketched an infeasibility proof which 
revealed that they had made one more assumption not included in my list:
numbers would be generated by successive calls to nat. In this case one
needs side effects, hence I had eliminated the one crucial prerequisite.

All other contributors had thought up isomorphic versions of the following
solution which generates the numbers on *backtracking* (which was my intention
in the first place):

	nat(X) :- nat1(X,0).

	nat1(X,X).
	nat1(X,Y) :- Z is Y+1, nat1(X,Z).

Well, what about its runtime behaviour? Somebody conjectured that "it should
run in O(n) on any decent Prolog implementation". True, but what is decent?
When I fiddled around looking for a solution I used an interpreter without
any optimization. All my attempts were O(n**2) and the above solution was no
exception! In fact it is a good example for the problem of nesting calls
that I mentioned in the original posting. With each number generated there
is one more pending call to nat1 and none of these calls are ever exited for
good. This primarily a space problem (and not my concern in this riddle). It
also means that with each number generated one needs one more variable
renaming to arrive at the answer substitution in terms of the variables of
the query, and this is a time problem. Seeing this dilemma I decided to post 
the question. 

Frustrated by the experience with the interpreter I had completely overlooked
the second important property of the proposed solution: the definition of
nat1 is tail-recursive and can be optimized by almost any Prolog *compiler*
in existence. The optimization consists of reusing the local variables of
nat1 in the recursive call instead of allocating a fresh set, thus removes
the overhead incurred by repetitive renamings and, voila, everything runs
linear! 

You see, whether or not a solution to my problem exists hinges on the
question of what you want to call a decent Prolog implementation. Funny
indeed!



		Klaus Noekel 


UUCP: ...!mcvax!unido!uklirb!noekel
Technical Details
Message-ID: <29400002@uklirb.UUCP>
Path: arc1-ca.pugleaf.net!utzoo!mnetor!uunet!seismo!mcvax!unido!uklirb!noekel

Show Full Headers
Complete Article Headers
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: arc1-ca.pugleaf.net!utzoo!mnetor!uunet!seismo!mcvax!unido!uklirb!noekel
From: noekel@uklirb.UUCP
Newsgroups: comp.lang.prolog
Subject: Prolog riddle summary - (nf)
Message-ID: <29400002@uklirb.UUCP>
Date: Tue, 28-Jul-87 10:26:00 EDT
Article-I.D.: uklirb.29400002
Posted: Tue Jul 28 10:26:00 1987
Date-Received: Thu, 30-Jul-87 06:57:42 EDT
Lines: 64
Nf-ID: #N:uklirb:29400002:000:2734
Nf-From: uklirb!noekel    Jul 28 15:26:00 1987