Newsgroups: comp.lang.prolog
Path: cantaloupe.srv.cs.cmu.edu!das-news2.harvard.edu!oitnews.harvard.edu!purdue!lerc.nasa.gov!magnus.acs.ohio-state.edu!math.ohio-state.edu!uwm.edu!chi-news.cic.net!newsfeed.internetmci.com!in1.uu.net!munnari.oz.au!cs.mu.OZ.AU!munta.cs.mu.OZ.AU!fjh
From: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Subject: Re: TRANSLATION BASED IMPLEMENTATION OF DCGs CONSIDERED HARMFUL (was: Strings in DCG-style Chart Parsing
Message-ID: <9530300.14904@mulga.cs.mu.OZ.AU>
Sender: news@cs.mu.OZ.AU (CS-Usenet)
Organization: Computer Science, University of Melbourne, Australia
References: <PEREIRA.95Sep30104755@alta.research.att.com> <1995Oct3.095758.26601@let.rug.nl> <PEREIRA.95Oct3195504@alta.research.att.com> <4563vn$aj7@idefix.CS.kuleuven.ac.be> <9529201.19103@mulga.cs.mu.OZ.AU> <46j4io$obl@sol.sun.csd.unb.ca>
Date: Sun, 29 Oct 1995 13:46:17 GMT
Lines: 197

Paul Tarau <tarau@info.umoncton.ca> writes:

>permute(Xs,Ys):-permute(Xs,[],Ys).
>
>permute([])-->[].
>permute([X|Xs])-->permute(Xs),insert(X).
>
>insert(X),[X]-->[].
>insert(X),[Y]-->[Y],insert(X).
>
>Try to make it work with a non-list representation of 'C'/3 !

Hey, this is backwards.  I thought the original problem you were
complaining of with DCGs was that they didn't support the use of
non-list representations.  Of course it is going to be difficult to
write `permute/2' without using lists, because the whole purpose
of `permute/2' is to permute lists.  But that doesn't mean that
DCGs can't be used for other problems which don't need or want lists.
They can -- I do it all the time.

I suppose if you consider `permute/2' to permute sequences, rather
than lists, and you want to to abstract away the representation
of those sequences, then this might be a reasonable challenge.
Here's an example implementation of `permute' done in such
a way as to be independent of how the sequences are represented.
It assumes that sequences are an abstract data type
with two predicates `empty_seq/0' and `non_empty_seq/3'.
`empty_seq(Seq)' binds `Seq' to an empty sequence.
`non_empty_seq(Seq, First, Rest)' succeeds if `Seq'
is a non-empty sequence whose first element is `First'
and whose remaining elements are the sequence `Rest'.

	permute(Xs, Ys) :- empty_seq(S), permute(Xs, S, Ys).

	permute([])-->[].
	permute([X|Xs])-->permute(Xs),insert(X).

	insert(X)-->insert_front(X).
	insert(X)-->delete_front(Y),insert(X),insert_front(Y).

	insert_front(Ch, S0, S) :- non_empty_seq(S, Ch, S0).
	delete_front(Ch, S0, S) :- non_empty_seq(S0, Ch, S).

That wasn't so hard, was it?

That code does assume translation based DCGs.
For a phrase/3 based implementation, you would need
to write it slightly differently:

	permute(Xs, Ys) :- empty_seq(S), phrase(permute(Xs), S, Ys).

	permute([])-->[].
	permute([X|Xs])-->permute(Xs),insert(X).

	insert(X)-->insert_front(X).
	insert(X)-->delete_front(Y),insert(X),insert_front(Y).

	phrase(insert_front(Ch), S0, S) :- non_empty_seq(S, Ch, S0).
	phrase(delete_front(Ch), S0, S) :- non_empty_seq(S0, Ch, S).

That sort of thing won't work with translation based DCGs, unfortunately,
because the additional clauses for phrase/3 wouldn't have the desired
effect.  It could however be made to work pretty easily by getting
term_expansion to expand clauses for phrase/3 as well as for '-->'/2.

>>>- DCG meta-programming with phrase/3 is expensive as it implies
>>>  expanding on the fly, with lot of structure-crunching
>>>  ....
>
>> I don't quite understand what you mean here.  Could you give an
>> example of what you mean by "DCG meta-programming with phrase/3",
>> and explain why it is expensive? 
>
>In
>
>a-->[1].
>b-->[2].
>start((a,b,b,a)).
>
>go(Xs):-start(P),phrase(P,Xs,[]).
>
>?-go(Xs).
>
>whatever you do in your implementation, phrase/3 will have at some
>point either to generate a(X,X1),b(X2,X3),b(X3,X4),a(X4,X) or to 
>meta-interpret (a,b,b,a) as if it had chained extra arguments.
>None of the alternatives seems cheap to me.

But why would you write code like that anyway?
Why wouldn't you write this as

	a-->[1].
	b-->[2].
	start--->a,b,b,a.

	go(Xs):-phrase(start,Xs,[]).

	?-go(Xs).
	
?

In that case, the only meta-interpretation going on is the
call to phrase/3.  With the usual term-expansion based implementation
of DCGs, phrase/3 is just another name for call/3, and compilers
can certainly generate quite good code for call/3.  That should
not be much overhead, but even that small overhead can be avoided.
In this case, the argument of call/3 is known at compile time,
so it could be unfolded, as if you had written:

	go(Xs) :- start(Xs,[]).

>> >sent:-ng,v.        ng:-art,n.
>> >art:- #the.        art:- #a.
>> >  n:- #cat.          n:- #dog.
>> >  v:- #walks.        v:- #sleeps.
>
>> Can you please tell me the declarative semantics of `sent'?
>> How about the declarative semantics of `art'?
>
>THE SEMANTICS IS AS SIMPLE AS THE ONE OF ORDINARY DCGs. JUST
>TRANSLATE #X TO [X] AND :- TO --> AND THEN USE THE
>`DECLARATIVE SEMANTICS' OF THE DCGs YOU ALREADY HAVE :-)

Translating `#X' to `[X]' is fine.
But translating `:-' to `-->' does cause trouble.
How can I tell whether something is a HAG or not?
If I see the code

	p :- q, r.

is `p/0' a HAG?  Is the declarative semantics of this code equivalent to
the declarative semantics of

	p :- r, q.

?

>> Translation-based DCGs have a simple translation-based declarative
>> semantics.  Do HAGs have a declarative semantics?  What are the
>> semantics of `,' in a language with HAGs - and is it related to logical
>> conjunction? 
>
>',' has the same semantics with HAGs as it has in DCGs, of course :-)
>
>More seriously, once you accept translation as a semantics for DCGs
>and I give you a translation from HAGs to DCGs we are not far apart.

I do accept translation semantics for DCGs, but only grudgingly -
the phrase/3 based semantics which I described in a recent post
to comp.lang.prolog is certainly more elegant.

The reason we are still a long way apart is that your translation from
HAGs to DCGs is not benign - it has the nasty effect of translating not
just HAGs to DCGs, but everything else too!  DCGs are useful for _some_
parts of programs, but I don't want _all_ parts of my programs to be DCGs.

>> Some of us consider declarative logical semantics to be an
>> important issue in logic programming.
>
>Indiscriminate use of valuable principles has often the adverse effect
>of deflating their meaning and value.

I agree, but I don't think I am being indiscriminate here.
Specifically, I wish to discriminate between the use of `:-'
and of `#' in HAGs.  The use of `#' would be fine if HAGs
used `-->' rather than `:-'.  It is the reuse of `:-' that causes
the problem.  `:-' already has an accepted meaning, and you
are changing that meaning quite dramatically.  A lot of simple
guarantees that exist in pure Prolog or in Mercury would go
out the window if you redefine `:-' in this fashion.

>'C'/3 based DCGs and HAGs can be seen as different implementations of
>the same concept.

Yes, but there is one fundamental difference, and that is that
DCGs preserve the simple declarative semantics of ordinary predicates
such as p/0 above, whereas HAGs destroy it.

>It seems that the strong type and mode information of Mercury would
>give even more opportunities for local-reuse (destructive update) if a
>HAG-style implementation of DCGs and I/O streams is used, than it is the
>case in Prolog (the hidden arguments can be overwritten in a
>deterministic AND-branch) and you seem to know when this is the case at
>compile time. You will have to work quite hard to infer this property
>back from the DCG translation.

I'm not convinced that HAGs would make structure reuse and
destructive assignment optimization any easier.  How will you know
that the hidden arguments aren't aliased?

One thing I know for sure, though -- I would rather have to do global
analysis to get efficient code than to have to do global analysis to
determine the declarative semantics!

--
Fergus Henderson             	WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au              	PGP: finger fjh@128.250.37.3
