Has someone made some code that translates code with accumulators to EDCGs?

Asking because you may never know unless you ask, and without asking the next thing you know a decade has passed before you know, and knowing to ask is even better than not knowing what to ask. If that makes sense, I should give you a badge. :wink:

So I have been in the land of EDCGs for a few days and creating steps on how to covert code with accumulators, code with DCGs, code with DCGs and accumulators, code with DCGs, accumulators and end of string to EDCGs and was wondering if someone has not already been there and written some code that can take standard code and convert it to EDCGs so I don’t have to.


Personal Notes

AFAIK EDCGs started with the Aquarius compiler. See thesis of Peter Lodewijk Van Roy

The thesis is available as two PDF files:


References

Extended DCGs in Prolog (James Cash blog)
Package “edcg” - Has syntax for use with SWI-Prolog
Examples - Examples from SWI-Prolog package EDCG
Prolog and Natural-Language Analysis by Fernando C. N. Pereira and Stuart M. Shieber (pdf)
A Unified Approach to Global Program Optimization by Gary A. Kildall (pdf)
Abstract Interpretation: ‘A Unified Lattice Model for Static Analysis Of Programs by Construction or Approximation of Fixpoints’ by Patrick Cousotand Radhia Cousot (pdf)
Towards Structured State Threading in Prolog by Dragan Ivanovic, José F. Morales, Manuel Carro, and Manuel Hermenegildo (pdf)
Lattice Theory by Garrett Birkhoff (pdf)

I haven’t (I used EDCGs from the start of my code) … but if your code uses meta-predicates such as maplist, you’ll need to write EDCG-aware variants on maplist and friends. Also, I found it useful to document each predicate with which EDCG accumulators/pass_info it uses.

1 Like

Oh, advanced EDCGs, haven’t reached that level yet, but now I know to keep an eye out for such. Thanks. :slightly_smiling_face:

I could really use some of that EDCG knowledge you have. Care to create a blog, page or something that we can learn from. :wink:

I know @jamesnvc finds them of use.

1 Like

I don’t have a lot to add to that blog posting.

It’s easy to accidentally type ‘–>’ instead of ‘–>>’. It’s also easy to forget an edcg:pred_info/3 fact – also, all the EDCG declarations need to be before any code that relies on EDCG expansion.

I recommend adding ?-check. at the end of your source files, which will catch some of such mistakes. I also use the rdet package to catch unexpected failures, which are often the result of making a small typo. listing/1 on an EDCG predicate is also useful for catching typos.

For EDCGs, ‘{}’ is optional for unexpanded goals; but I use it anyway, for consistency with regular DCGs.

FWIW, here is my code for handling maplist with EDCGs, with accumulators foo and bar, plus a “global” value file_meta that gets passed as a single parameter (and whose value is access by the goal Meta/file_meta … if I need to get the value of the bar accumulator, I used Bar/bar/Bar). I wrote this code by a straightforward transformation fromlibrary(apply), with different naming conventions (you might also disagree with the “+” and "-"s in the meta_predicate directive and my is det comments).

edcg:acc_info(foo, T, Out, In, Out=[T|In]). % DCG-like accumulator
edcg:acc_info(bar, Arg, In, Out, bar_accum(Arg, In, Out)). % Uses rbtrees
edcg:pass_info(file_meta). % Dict with description of file being processed

:- meta_predicate
    maplist_foo_bar(6, +, +, -, +, -, +),
    maplist_foo_bar(7, +, -, +, -, +, -, +),
    maplist_foo_bar_(+, 6, +, -, +, -, +),
    maplist_foo_bar_(+, 7, -, +, -, +, -, +).

edcg:pred_info(maplist_foo_bar, 2,  [foo,bar,file_meta]).
edcg:pred_info(maplist_foo_bar, 3,  [foo,bar,file_meta]).
edcg:pred_info(maplist_foo_bar_, 2, [foo,bar,file_meta]).
edcg:pred_info(maplist_foo_bar_, 3, [foo,bar,file_meta]).

%! maplist_foo_bar(:Pred, +L:list)//[foo,bar,file_meta] is det.
maplist_foo_bar(Pred, L) -->> maplist_foo_bar_(L, Pred).
maplist_foo_bar_([], _Pred) -->> [ ].
maplist_foo_bar_([X|Xs], Pred) -->>
    call(Pred, X):[foo,bar,file_meta],
    maplist_foo_bar_(Xs, Pred).

%! maplist_foo_bar(:Pred, +L0:list, -L:list)//[foo,bar,file_meta] is det.
maplist_foo_bar(Pred, L0, L) -->> maplist_foo_bar_(L0, Pred, L).
maplist_foo_bar_([], _Pred, []) -->> [ ].
maplist_foo_bar_([X|Xs], Pred, [Y|Ys]) -->>
    call(Pred, X, Y):[foo,bar,file_meta],
    maplist_foo_bar_(Xs, Pred, Ys).
2 Likes

That deserves more than a simple heart, so Thanks!.

It will take me some time to understand it, but I am sure others will be thinking about how they write their code after looking at this.

I have more questions about EDCGs but have not run out of options on figuring them out so I might have more questions down the road. :slightly_smiling_face:

Also worth mentioning that the use of multifile predicates for EDCG declarations is inherently broken. If you use multiple EDCGs, you need to ensure that declarations (i.e. accumulators, passed arguments, and predicates with hidden EDCG arguments) are unique even if each EDCG is encapsulated in its own module. Otherwise there’s a risk of the previously loaded declarations being used instead of the intended ones in the module you’re compiling.

2 Likes