Article View: comp.lang.prolog
Article #3719Re: Copying
From: Richard A. O'Keefe
Date: Thu, 20 Oct 1988 07:08
Date: Thu, 20 Oct 1988 07:08
84 lines
3483 bytes
3483 bytes
In article <16400001@clio> gerdeman@clio.las.uiuc.edu writes:
>Sterling and Shapiro give the following procedure for copying:
>copy(X,Y):- assert('$foo'(X)),retract('$foo'(Y)).
There are two problems with that: retract/1 is prepared to backtrack.
In DEC-10 Prolog and C Prolog, a choice-point will be left behind even
if there is just the one clause for $foo. That's not a mistake, that's
the way it _has_ to work. Quintus Prolog 2.0 and later use a slightly
different definition of assert and retract ("a running predicate does
not notice any changes to its clauses") which means that a choice
point will not be left behind in this case. With other Prolog systems,
check the manual (and use whatever resource measurement tools are offered
to find out what is really happening). But that's not the only problem.
| ?- copy(a, b).
fails, leaving the clause '$foo'(a) in the data base. The next call,
| ?- copy(c, X).
will pick up that clause, binding X = a, and leave '$foo'(c) in the
data base. And so it goes...
If you're going to do this, you have to write
copy_term(Original, Copy) :-
asserta('$foo'(Original)),
retract('$foo'(Working)),
!,
Copy = Working.
(And people wonder why I recommend _not_ changing the data base unless
you absolutely have to.)
>I have found the following to be much faster:
>copy(X,Y):- findall(Z, Z = X,[Y]).
>This only works with findall not setof or bagof. Can anyone
>explain why this works?
It works because findall(Template, Generator, List) does
mark a stack
( call(Generator)
make a copy of the current instance of Template
and push it on the stack
fail
; true
),
Answer := []
while there is something above the mark do
Answer := [pop the top copy off the stack | Answer]
pop the mark
List = Answer
An even simpler form of the call which will accomplish this effect is
copy_term(Original, Copy) :-
findall(Original, true, [Copy]).
This may be faster than the assert+retract versions in some systems, or it
may be slower. (The implementation shown in Clocksin & Mellish, for
example, would solve this query by performing TWO asserts and TWO
retracts, so it would be slower than the Sterling & Shapiro suggestion.)
If your Prolog system hasn't got findall/3 (it is a library predicate
in DEC-10 Prolog and Quintus Prolog, for example, not built in), you can do
copy_term(Original, Copy) :-
bagof(Original, true, [Copy]).
Or in Quintus Prolog you could call the built-in predicate copy_term/2.
>In general, I have discovered, destructive
>variable bindings embedded within findall have no global effect.
>Again this is not the case with setof and bagof. Very peculiar
>isn't it?
(a) What's a "destructive variable binding"?
(b) If you mean that setof/3 and bagof/3 enumerate bindings for the
free variables (the variables in the Generator which are not
explicitly quantified and do not appear in the Template) and that
findall/3 doesn't, that hardly counts as peculiar. That's what
they are FOR.
Technical Details
Message-ID:
<557@quintus.UUCP>Path:
arc1-ca.pugleaf.net!utzoo!attcan!uunet!lll-winken!arisia!quintus!okReferences:
<16400001@clio>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!attcan!uunet!lll-winken!arisia!quintus!ok From: ok@quintus.uucp (Richard A. O'Keefe) Newsgroups: comp.lang.prolog Subject: Re: Copying Message-ID: <557@quintus.UUCP> Date: 20 Oct 88 07:08:14 GMT References: <16400001@clio> Sender: news@quintus.UUCP Reply-To: ok@quintus.UUCP (Richard A. O'Keefe) Organization: Quintus Computer Systems, Inc. Lines: 83