Re: Extended DCG?

"Abdallah, Samer" <[email protected]>
Newsgroups gmane.comp.ai.prolog.swi
Message-ID <[email protected]>
Hi Jan,

See below…

On 13 Feb 2014, at 11:01, Jan Wielemaker <[email protected]>
 wrote:

> Hi Samer,
> 
> Ok.  I see two developments:
> 
>  - Introduction of real strings in V7 (compatible to ECLiPSe and quite
>    likely YAP at some point).
>  - Future directions to a more (soft) typed language.
> 
> There has also been fierce fights about this in the ISO group.  I don't
> know the current status.
> 
> I see several solutions:
> 
>  1. Keep phrase checking and add a new non-checking predicate.
>  2. Use Markus' state interface (exploiting push-back and a
>     one-element list).
>  3. Remove checking and add some checking library that
>     wraps phrase calls with type checking.
>  4. Only disallow string objects in phrase/3.
>  5. Auto-convert string objects in phrase/3 to code lists.
> 
> (1) is probably the best from a type-checking viewpoint. I don't know
> how to name the predicate (you seem to struggle too). I think the name
> should not refer to `gammar'. You are threading state that has nothing
> to do with the notion of grammars. Your bodies must also be limited as
> (list) literals make no sense. To me, it still seems you're misusing an
> implementation vehicle for something it was not supposed to do.  In
> my experience that is asking for a breakdown sooner or later.

This sounds ok to me. Maybe it could be called runstate/3, like in
the Haskell state monad. I don't think it's misusing anything. You make my point
for me: the list literal is the *only* operation that doesn't make sense -
all the other constructs are great and useful. To me, this suggests that
the list type checking belongs on the list literal, not on the phrase/3
predicate. Re. the point below, the one element list with push back
is just as much of a 'misuse' of the grammar system--it's just enough to
fool the putative type checker that everything is ok, but it has as much
to do with grammars as forgetting about lists and allowing any type
to be threaded. 

With full type inference, this would all work perfectly.
phrase/3 would have polymorphic type

	phrase/2 :: pred( dcg_goal(A), A, A),

where dcg_goal(A) is either a callable of type pred(A,A)
or a DCG construct involving (,), (;) (->), {} etc and subgoals
of type dcg_goal(A). The list literal would be restricted to 
list types: if X is a literal list of type list(A), then 

	X :: dcg_goal(list(A)).

As soon as a list literal appears anywhere in a DCG goal, then
the type constraint will be propagated up, so the
overall goal G will have type dcg_goal(list(A)). If you
give this as the first argument to phrase/3, then second
two arguments would have to be lists.

The only fly in the ointment is the convention of using
the empty list [] as a no-op - according to this scheme,
it's type would still be dcg_goal(list(A)) and therefore no
good for arbitrary state types. All that would be needed is
an alternative, fully polymorphic no-op, e.g. 

	noop//0 :: dcg_goal(A).
	noop(X,X).


> 
> (2) seems pretty elegant to me.  I don't really see your argument
> for `another layer of meta predicates'.  I see two rather simple
> predicates that we should be able to inline if necessary.  The
> only overhead should be a list cell.

As I said above, it seems like a needless complication and it
is just as much an abuse of the grammar mechanism as allowing
arbitrary states.

Re. the other points below, I'm a bit behind the curve with all
the developments on string representations. If a more efficient string
representation is needed, again, the only DCG operation that needs
to care is the list literal one. If the string is in a packed array
of characters, then one sensible representation of state is a 
pair (Position,String). If we let pair(X,Y) be the type of comma
separated pairs, then list literals could have several alternative types:

	<list(A)>       :: dcg_goal(list(A)).  
	<list(char)> :: dcg_goal(pair(int,string)).
	<list(code)>:: dcg_goal(pair(int,string)).

There could also be a 'string literal' which would also work
with the pair(int,string) representation. 
	<string>      :: dcg_goal(pair(int,string)).
The implementations of these in the *parsing* direction are 
obviously trivial. In the *generating* direction, the list 
representation looks like the winner.

According to this scheme, phrase/3 would *never* accept 
string in the last two argument positions. It would be reasonable,
however, to allow phrase/2 in the parsing direction to accept a 
string and convert it to either a list or a pair(int,string) according 
to the type of the DCG goal.

I realise that all of this (perhaps) requires a type system which 
SWI does not have, but my point is that adding type checking
in an ad hoc way seems like an unsatisfying half-way house -
you loose the flexibility of an untyped system but you do not
gain the power of a proper type system.

Anyway, back to the question at hand - I like option 1.  I dislike
option 2. I share your reservations about options 3,4 and 5.
I also think the pair(int,string) representation might be worth
pursuing.


cheers,
Samer


> 
> (3-5) makes we can never introduce more validation later.
> 
> (3) leaves people doing phrase("he", "hello") completely in the
> dark with a 'false'.  Unless they load some library, but that
> probably only happens after significant frustration.
> 
> (4) might be a practical solution.  Feels hacky though.  Why can I
> use an atom as a state, but not a string?
> 
> (5) Would make many things work as before, but for the wrong reason.
> If there was only phrase/2 I might have been in favor, but the result
> below is hard to explain.
> 
>  ?- phrase("he", "hello", X).
>  X = [108, 108, 111].
> 
> My preference goes to either (1) or (2), adding the predicates to
> the system and properly documenting the issue.
> 
> Support/preference/other solutions?
> Names for predicates if we go (1) or (2)?
> 
> 	Cheers --- Jan
> 
> P.s.	Ideally, I'd like something else for threading state, such as
> 	Tom's coroutining proposal, or possibly something simpler.
> 
> 
> On 02/12/2014 07:48 PM, Abdallah, Samer wrote:
>> Hi all,
>> I would just like to use this opportunity to request again that phrase/3 be
>> allowed to work with arbitrary types in the last two positions, not just
>> lists, or an alternative, say gphrase/3  (for generalised phrase), or
>> rundcg/3 which works exactly like phrase/3 but allows arbitrary types.
>> Or even better, put phrase/3 back how it was and introduce a type
>> checking list_phrase/3 or safe_phrase/3 for people who want that.
>> 
>> It used to be the case that an extended DCG for writing a transducer
>> as  Alan would like, was easy to write using ordinary DCG notation.
>> The type of the threaded argument would be a pair of lists (L,R)
>> instead of just one list. In my DCG library I have some DCG rules for
>> working with this conveniently. For example, operators (\<)//1 and (\>)//1
>> apply a DCG phrase to the left or right member of the pair:
>> 
>> :- op(800, \<, fy).
>> :- op(800, \>, fy).
>> 
>> \<(P, (L1,R), (L2,R)) :- phrase(P,L1,L2).
>> \>(P, (L,R1), (L,R2)) :- phrase(P,R1,R2)
>> 
>> Then you can do things like \< integer(X) to read an integer from
>> from the left sequence and \> [int(X)] to write a term to the right, and so on.
>> Alan's scenario is easily and efficiently dealt with.
>> 
>> Forcing us to use lists for the arguments to phrase/3 forces an ugly
>> encoding of the pair in a singleton list, e.g. as [(L,R)], and, if the list
>> is [X] and we already have a bunch of predicates that want to work
>> on X,  forces an unnecessary layer of meta-predicates to get through
>> the wrapping.
>> 
>> For the moment, I have deleted the two offending lines from boot/dcg.pl
>> in my local installations, but of course, this is not good for the portability
>> of my code!
>> 
>> cheers,
>> Samer
>> 
>> 
>> (
>> On 11 Feb 2014, at 16:51, Alan Baljeu <[email protected]>
>>  wrote:
>>> I have a scenario where I'm mapping a list to a second list, but it's not 1 to 1.  For this, it would be nice to use an extended DCG, that supports two independent lists.  Does such a thing exist?
>>> 
>>> Alan Baljeu
>>> -------------- next part --------------
>>> HTML attachment scrubbed and removed
>>> _______________________________________________
>>> SWI-Prolog mailing list
>>> [email protected]
>>> https://lists.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog
>>> 
>> 
>> -------------- next part --------------
>> A non-text attachment was scrubbed...
>> Name: signature.asc
>> Type: application/pgp-signature
>> Size: 495 bytes
>> Desc: Message signed with OpenPGP using GPGMail
>> URL: <https://lists.iai.uni-bonn.de/pipermail/swi-prolog/attachments/20140212/e49a2d8e/attachment.bin>
>> _______________________________________________
>> SWI-Prolog mailing list
>> [email protected]
>> https://lists.iai.uni-bonn.de/mailman/listinfo.cgi/swi-prolog
>> 
> 
> 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 495 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <https://lists.iai.uni-bonn.de/pipermail/swi-prolog/attachments/20140213/be2a6d9b/attachment.bin>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.