| Did you know ... | Search Documentation: |
| Packs (add-ons) for SWI-Prolog |
| Title: | EDCG surface syntax over a record-threaded (Ludemann) back-end |
|---|---|
| Rating: | Not rated. Create the first rating! |
| Latest version: | 0.1.0 |
| SHA1 sum: | 9e32ae68c3fdda7a9e6799cc2f9fa50701d301d3 |
| Author: | redcg contributors <redcg@localhost> |
| Maintainer: | redcg contributors <redcg@localhost> |
| Requires: | prolog>=9.0 |
No reviews. Create the first review!.
| Version | SHA1 | #Downloads | URL |
|---|---|---|---|
| 0.1.0 | 1651f5c9f4392dd07573a3ada20897b79651926c | 1 | https://github.com/arizvisa/redcg.git |
| 9e32ae68c3fdda7a9e6799cc2f9fa50701d301d3 | 1 | https://github.com/arizvisa/redcg.git |
redcg lets you write multi-accumulator predicates in EDCG's syntax —
acc_info/5, pass_info/1, pred_info/3 declarations and -->> rules with the
built-in dcg accumulator, bare-list terminals, [T]:Acc, X/Acc, Acc/X,
X/Acc/Y and insert/2 — while the expansion runs on Peter Ludemann's
record-threading technique instead of EDCG's per-accumulator argument threading.
Backwards-compatible with library(edcg): an EDCG program runs under redcg
by swapping library(edcg)→library(redcg) and the `edcg:→redcg:` declaration
prefix. EDCG's own synopsis, unique, and puzzle example programs pass
verbatim under redcg (see prolog/redcg.plt).
Like library(edcg), the module exports nothing but its operators and an
opt-in sentinel. You contribute declarations as `redcg:`-qualified multifile
facts (note: facts, not directives), and you enable expansion in a module by
importing redcg.
% one-time, from the SWI toplevel:
?- pack_install(redcg). % from a registry/URL, or…
?- pack_install('file:///path/to/redcg'). % …from a local checkout (dir URL)
Then, e.g. in `~/.config/swi-prolog/init.pl`:
:- use_module(library(redcg)).
use_module/1 at the top of any file (or a module) is the opt-in signal —
only importing modules get -->> expansion; everything else is left untouched
(verified: a -->> term in a non-importing module stays a plain term).
:- use_module(library(redcg)).
% declarations are redcg:-qualified FACTS (like edcg:acc_info/5 in EDCG):
redcg:acc_info(count, X, In, Out, plus(X, In, Out)).
redcg:acc_info(items, X, In, Out, Out = [X|In]). % collecthead (reversed)
redcg:pass_info(limit).
redcg:pred_info(tag_e, 1, [count, items, limit]).
% -->> rules, exactly as in EDCG:
tag_e([]) -->> [].
tag_e([H|T]) -->> L/limit, % V/Acc reads the passed value
( { H < L } -> [1]:count, [H]:items ; [] ),
tag_e(T).
% call with EDCG's per-accumulator In/Out arg pairs (acc = +2 args, pass = +1):
?- tag_e([10,30,20,40,5], 0, Count, [], Items, 25).
% Count = 3, Items = [5,20,10].
Declarations must appear before the -->> rules that use them (the field
layout is computed from the declared facts at expansion time).
Benchmarked on SWI 10.0.2, flattening a 200×200 matrix (straight accumulation):
| approach | relative | why |
|---|---|---|
real library(edcg) | fastest | threads only the fields a clause touches, each a bare arg |
| redcg (this pack) | ~2× slower than EDCG | one :- record compound is rebuilt on every field write |
| dict-threaded DCG | ~5× slower than record | get_dict/`.put` call overhead |
Ludemann's ~40% win was measured against dicts, not EDCG. So reach for redcg
when you want EDCG ergonomics + named, inspectable library(record) state,
not when the goal is to beat EDCG on raw accumulation speed. For a single piece
of state, a plain DCG still beats all three.
begin_of_file term-expansion resets per-file emission flags so a re-consult
re-emits everything (a persistent flag would survive reload and leave the
generated wrappers missing — a real bug, now covered).-->> rule in a file, redcg emits a `:- record redcg_state(...)`
directive — library(record)'s own expansion then turns it into
make_/get_/set_ accessors (a term_expansion-emitted :- record is
re-expanded downstream). It also emits one public wrapper per predicate.-->> bodies expand by threading the single record Sin -> Sout, with field
reads/writes inlined to plain unification (no accessor call survives).
Because state is a rigid record (not an open difference list), the branches
of ;/-> must NOT share one output-record variable — unifying two
differently-updated redcg_state(...) terms at expansion time cross-links their
field vars. Each arm therefore threads its own fresh output record,
reconciled to the shared output by a runtime = (like DCG translation of
disjunction). This is the exact hazard EDCG's _merge_acc exists to handle.
-->> rules. redcg emits one shared
:- record at the first rule in a file, so every acc_info/pass_info must
be declared above it (EDCG's own example files all follow this).redcg_state compound. (EDCG has the same per-file view.)Acc/X (read-final) and X/Acc/Y (read-current-and-final) are supported
by threading the clause-final record: Acc/X / the Y in X/Acc/Y unify
with the accumulator's value at the end of the clause, matching EDCG.-->> bodies inherit EDCG's own caveat; verify the expansion with
listing/1 if a rule cuts (note: the SWI pretty-printer can garble a
nested--> clause; write_canonical/1 shows the true term).
prolog/redcg.plt — a plunit suite (12 tests, incl. EDCG backwards-compat regressions). This is a pure-Prolog pack, so
(like library(edcg)) the tests are not run automatically on install:
pack_install/2's test(true) build step only fires for packs with foreign
(C) components. Run them manually against a checkout:
?- [library(redcg)],
consult('prolog/redcg.plt'),
load_test_files([]),
run_tests.
% % All 12 tests passed
Pack contains 4 files holding a total of 23.8K bytes.