🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.prolog
Article #388

Re: different Prologs?

#388
From: Richard O'Keefe
Date: Tue, 10 Oct 1989 02:02
124 lines
4905 bytes
In article <111000002@uxa.cso.uiuc.edu>, ddgg0881@uxa.cso.uiuc.edu writes:
> I have two questions about Prolog implementations:

> 1. I've discovered one implementation that gives 3 solutions to
> member(a,[a,a,a]) even though there aren't 3 ways to instantiate
> variables.  Another implementation I've used gives only one solution.
> Which way is standard? Are there arguments for doing things one way
> or the other?

There is precisely one "standard" way of defining member/2,
modulo spelling of variable names and dot-vs-bracket syntax for lists:

	member(X, [X|_]).
	member(X, [_|L]) :-
		member(X, L).

Prolog does *not* find solutions.  Prolog finds **proofs**, and shows you
(part of) the substitution it found for each proof.  The goal
	?- member(a, [a,a,a]).
has three proofs.  So that's the number of times Prolog should come back
to you with an answer substitution.  However, there is a fine point to do
with the user interface.  Many Prolog systems check the query that you
type in, and if it hasn't got any variables, just say "yes" or "no".
NU Prolog does this, except it says "true" or "false".  Transcript:
	% np
	NU-Prolog 1.4
	1?- member(a, [a,a,a]).
	true.
However, if you put a variable in there to fool it, you will see that it
is prepared to find the other proofs.  Transcript:
	2?- X=dummy, member(a, [a,a,a]).
	X = dummy ;
	X = dummy ;
	X = dummy ;
	fail.

Another way of seeing that the three proofs are found is
	3?- member(a, [a,a,a]), write(*), fail.
	***fail.

> 2. I find reading text files very painful in Prolog because you
> always have to keep a lookahead character.

So?  You need a lookahead character for tokenising anyway, all you have
to do is remember not to drop it on the floor.  Just write down your DFSA
and the transcription into Prolog is direct, but DIRECT.

> This way of doing things doesn't feel like Prolog.

Of course not, because it uses side effects.  Depending on the size of
the files you want to process, and the memory capacity of your machine,
you might want to consider slurping the entire file into memory as a
list of character codes, and parsing that using grammar rules.  I'm
quite serious about this:

	get_file(FileName, Chars) :-
		seeing(CurrentInput),
		see(FileName),
		get0(C),
		slurp(C, Cs),
		seen,
		see(CurrentInput),
		Chars = Cs.

	slurp(-1, []) :- !.
	slurp(C, [C|Cs]) :-
		get0(D),
		slurp(D, Cs).

In SICStus Prolog 0.6 it takes about 6 seconds to read 30kbytes this
way on a discless Sun-3/50.

> One of the main selling points of Prolog
> is the efficient way that it backtracks upon failure.  Are there any
> implementations of Prolog that allow 'get' or 'get0' to backtrack
> and unread characters?

Yes.  Sort of.  If you are reading from a file there is no problem.  But
what if you are reading from a source that can't back up?  (For example,
reading from a terminal --very likely-- or a UNIX command --I do that
quite often-- or a named pipe --quite possible-- or a streaming tape
--just joking.)  Then the Prolog system would have to buffer an
arbitrary amount of information just in case you decided to back up.
Your Prolog system probably provides some kind of file positioning
feature.  Just for grins, here's how to hook it into grammar rules.

	file(NonTerminal, File) :-
		open(File, read, Stream),
		stream_position(Stream, Position),
		phrase(NonTerminal, @(Stream,Position), @(Stream,End)),
		stream_position(Stream, _, End),	% high-water mark
		get0(-1).				% is end-of-file

	get_char(Char, @(Stream,OldPos), @(Stream,NewPos)) :-
		stream_position(Stream, _, OldPos),	% go to OldPos
		get0(Char),				% pick up Char
		Char >= 0,				% check not EOF
		stream_position(Stream, NewPos).	% where are we now?

Now your grammar rules, instead of saying
		[Char]
will say	get_char(Char)
as a non-terminal.  In NU Prolog, which provides the non-portable
ftell/2 and fseek/3 constructs (they are fine in UNIX, but not so good in
VMS or MVS or CMS), it's even simpler:

	stream_phrase(NonTerminal, Stream) :-
		open(File, read, Stream),		
		ftell(Stream, Start),
		fseek(Stream, 0, end),
		ftell(Stream, Finish),
		call(NonTerminal, @(Stream,Start), @(Stream,Finish)).

	get_char(Char, @(Stream,OldPos), @(Stream,NewPos)) :-
		plus(1, OldPos, NewPos),
		fseek(Stream, OldPos, beginning),
		get0(Char),
		Char >= 0.

	call(Closure, X1, X2) :-
		Closure =.. L0,
		append(L0, [X1,X2], L2),
		Goal =.. L2,
		call(Goal).
Technical Details
Message-ID: <2365@munnari.oz.au>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!uwm.edu!gem.mps.ohio-state.edu!ginosko!uunet!munnari.oz.au!cs.mu.oz.au!ok
References: <111000002@uxa.cso.uiuc.edu>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!uwm.edu!gem.mps.ohio-state.edu!ginosko!uunet!munnari.oz.au!cs.mu.oz.au!ok
From: ok@cs.mu.oz.au (Richard O'Keefe)
Newsgroups: comp.lang.prolog
Subject: Re: different Prologs?
Message-ID: <2365@munnari.oz.au>
Date: 10 Oct 89 02:02:18 GMT
References: <111000002@uxa.cso.uiuc.edu>
Sender: news@cs.mu.oz.au
Lines: 124