.in DCG is there a way to have hidden argument i.e. argument is passed in the top rule , but I dont mention it in the rest of the rules , but i still have access to it.
S(Ctx,A,B) --> ...
R1(A) --> ....
R2(A) --> ..R5(A), { write(Ctx) }
R3(A) --> ..add2ctx(abc,Ctx), remove4ctx(bcd,Ctx)..
the same way that DCG is syntax-sugar over difference lists I just want to skip declaring a variable it in the rules head and when I call another rule ?
No there is not. Whenever data has to be passed to a clause, it must be done so explicitly. You cannot define a piece of "context information" implicitly visible to all DCG roles.
But there is this note in the SWI-Prolog manual:
phrase/3
A portable solution for threading state through a DCG can be implemented
by wrapping the state in a list and use the DCG semicontext facility.
Subsequently, the following predicates may be used to access and modify > the state.
state(S), [S] --> [S].
state(S0, S), [S] --> [S0].
So the idea here is that you have term that describes a "current state" that you hot-potatoe from one DCG rule to the next by
Getting it from the input list
Transforming it from a state S0 to a state S
Then putting it back onto the list so that it is available for the next rule.
For example
state(S), [S] --> [S].
does not modify the state and just pushes it back on the list.
But
state(S0, S), [S] --> [S0].
grabs the state S0, maps it to S and put it back onto the list. That should be the idea I think. But in that example, there should probably be something more in the body, namely a call to some p(S,S0)...
Is not completely clear what you want to accomplish. The implicit arguments of a grammar rule are used for threading state as described e.g. in David's answer. It's however also possible to share implicit logical variables with all grammar rules (but note that these cannot be used for threading state). This can be easily accomplished by encapsulating your grammar rules in a Logtalk parametric object. For example:
:- object(grammar(_Ctx_)).
:- public(test/2).
test(L, Z) :-
phrase((a(Z); b(Z)), L).
a(Y) --> [aa, X], {atom_concat(X, _Ctx_, Y)}.
b(Y) --> [bb, X], {atom_concat(_Ctx_, X, Y)}.
:- end_object.
Some sample queries:
?- {grammar}.
% [ /Users/pmoura/grammar.lgt loaded ]
% (0 warnings)
true.
?- grammar(foo)::test([aa,cc], Z).
Z = ccfoo .
?- grammar(foo)::test([bb,cc], Z).
Z = foocc.
Would this work in your case? You can run this example with all Logtalk supported Prolog systems. You can also read more about parametric objects and parameter variables at https://logtalk.org/manuals/userman/objects.html#parametric-objects
In SWI-Prolog there is a ready-to-use and battle-proven pack, that builds on the DCG concept.
It does require a bit of learning, but don't fear, it's well supported.
Related
How to make this (or something similar) work in Prolog:
belief(john,red(apple)).
belief(peter,red(apple)).
X :- belief(john,X), belief(peter,X).
And get true. for the following query (while consulting above):-
?- red(apple).
First, it's useful to define a little helper to capture when all (relevant) persons believe something:
all_believe(Belief) :-
belief(john, Belief),
belief(peter, Belief).
Then you can define, for example:
red(Object) :-
all_believe(red(Object)).
green(Object) :-
all_believe(green(Object)).
And with your given set of beliefs you get:
?- red(apple).
true.
?- green(apple).
false.
This works. It requires you to define similar rules for any term that you want to use as a belief.
You can make this a bit shorter with macro definitions using term_expansion:
term_expansion(declare_belief(Belief),
Belief :- all_believe(Belief)).
This means that every top-level definition in your source code of the form declare_belief(Belief) should be treated as if you had written Belief :- all_believe(Belief) instead (with the variable Belief substituted appropriately).
So now you can just write this:
declare_belief(red(_)).
declare_belief(green(_)).
and it will be treated exactly like the longer definitions for red(Object) and red(Object) above. You will still have to write this kind of declaration for any term that you want to use as a possible belief.
Prolog does not allow the head of a rule to be just a variable. The head must be a nonvar term, whose functor (i.e., name and arity) identifies the predicate being defined. So, a possible solution would be something like this:
true_belief(X) :-
belief(john, X),
belief(peter, X).
belief(john, red(apple)).
belief(peter, red(apple)).
Examples:
?- true_belief(red(apple)).
true.
?- true_belief(X).
X = red(apple).
I'm writing a code generator that converts definite clause grammars to other grammar notations. To do this, I need to expand a grammar rule:
:- initialization(main).
main :-
-->(example,A),writeln(A).
% this should print ([a],example1), but this is a runtime error
example --> [a],example1.
example1 --> [b].
But -->(example, A) doesn't expand the rule, even though -->/2 appears to be defined here. Is there another way to access the definitions of DCG grammar rules?
This is a guess of what your are expecting and why you are having a problem. It just bugs me because I know you are smart and should be able to connect the dots from the comments. (Comments were deleted when this was posted, but the OP did see them.)
This is very specific to SWI-Prolog.
When Prolog code is loaded it automatically goes through term expansion as noted in expand.pl.
Any clause with --> will get expanded based on the rules of dcg_translate_rule/2. So when you use listing/1 on the code after it is loaded, the clauses with --> have already been expanded. So AFAIK you can not see ([a],example1) which is the code before loading then term expansion, but example([a|A], B) :- example(A, B) which is the code after loading and term expansion.
The only way to get the code as you want would be to turn off the term expansion during loading, but then the code that should have been expanded will not and the code will not run.
You could also try and find the source for the loaded code but I also think that is not what you want to do.
Based on this I'm writing a code generator that converts definite clause grammars to other grammar notations. perhaps you need to replace the code for dcg_translate_rule/2 or some how intercept the code on loading and before the term expansion.
HTH
As for the error related to -->(example,A),writeln(A). that is because that is not a valid DCG clause.
As you wrote on the comments, if you want to convert DCGs into CHRs, you need to apply the conversion before the default expansion of DCGs into clauses. For example, assuming your code is saved to a grammars.pl file:
?- assertz(term_expansion((H --> B), '--->'(H,B))).
true.
?- assertz(goal_expansion((H --> B), '--->'(H,B))).
true.
?- [grammars].
[a],example1
true.
I am trying to implement a Prolog program that can interact with java. To do this I use JPL as the Prolog/Java interface.
I am looking for a mechanism that allows me to execute actions automatically when the conditions become true.
The conditions are also represented by predicates. I have tried to use the predefined predicate "when/2", the problem is that as specified in the documentation here, the condition must be one of these:
nonvar(X)
ground(X)
?=(X, Y)
(Cond1, Cond2)
(Cond2; Cond2)
The last two conditions seem the ones I should use, but I could not make them work.
What do I need to change to make make my own conditions ?
Please, consider J as a local Prolog variable here.
:- use_module(library(jpl)).
:- use_module(library(when)).
should_engage(J) :-
jpl_get(J, 'shouldEngage', V),
V==true,
jpl_get(J, 'players', P),
jpl_call(P, 'canSeeEnemies', [], R),
R==true,
jpl_get(J, 'weaponry', W),
jpl_call(W, 'hasLoadedWeapon', [], R),
R==true.
call_java(J) :-
jpl_call(J, 'stateEngage', [], R).
when(should_engage(X), call_java(X)).
When/1 is part of the coroutining infrastructure that triggers actions on variable instantiation. It uses attributed variables in the background. So, if your J
is normally a variable that can get bound at some time you can do
...,
when(nonvar(X), propagate(X)).
propagate(X) :-
should_engage(X),
call_java(X).
Or
propagate(X) :-
( should_engage(X)
-> call_java(X)
; true
).
The first version will cause the instantiation of X to fail if should_engage/1 fails. The latter version not.
If it is not the binding of a variable that may make should_engage/1 true you'll need to find some other trigger or possibly have a thread that monitors the environment at intervals and propagates.
Note that calling non-logical constructs from when/1 typically makes little sense because Prolog's computation may backtrack, unbinding X and rebinding it again to the same or a different value and thus your propagation may be called many times with
different or the same value.
I'm trying for the moment to keep my lexer and parser separate, based on the vague advice of the book Prolog and Natural Language Analysis, which really doesn't go into any detail about lexing/tokenizing. So I am giving it a shot and seeing several little issues that indicate to me that there is something obvious I'm missing.
All my little token parsers seem to be working alright; at the moment this is a snippet of my code:
:- use_module(library(dcg/basics)).
operator('(') --> "(". operator(')') --> ")".
operator('[') --> "[". operator(']') --> "]".
% ... etc.
keyword(array) --> "array".
keyword(break) --> "break".
% ... etc.
It's a bit repetitive but it seems to work. Then I have some stuff I don't completely love and would welcome suggestions on, but does seem to work:
id(id(Id)) -->
[C],
{
char_type(C, alpha)
},
idRest(Rest),
{
atom_chars(Id, [C|Rest])
}.
idRest([C|Rest]) -->
[C],
{
char_type(C, alpha) ; char_type(C, digit) ; C = '_'
},
idRest(Rest).
idRest([]) --> [].
int(int(Int)) --> integer(Int).
string(str(String)) -->
"\"",
stringContent(Codes),
"\"",
{
string_chars(String, Codes)
}.
stringContent([C|Chars]) -->
stringChar(C), stringContent(Chars).
stringContent([]) --> [].
stringChar(0'\n) --> "\\n".
stringChar(0'\t) --> "\\t".
stringChar(0'\") --> "\\\"".
stringChar(0'\") --> "\\\\".
stringChar(C) --> [C].
The main rule for my tokenizer is this:
token(X) --> whites, (keyword(X) ; operator(X) ; id(X) ; int(X) ; string(X)).
It's not perfect; I will see int get parsed into in,id(t) because keyword(X) comes before id(X). So I guess that's the first question.
The bigger question I have is that I do not see how to properly integrate comments into this situation. I have tried the following:
skipAhead --> [].
skipAhead --> (comment ; whites), skipAhead.
comment --> "/*", anything, "*/".
anything --> [].
anything --> [_], anything.
token(X) --> skipAhead, (keyword(X) ; operator(X) ; id(X) ; int(X) ; string(X)).
This does not seem to work; the parses that return (and I get many parses) do not seem to have the comment removed. I'm nervous that my comment rule is needlessly inefficient and probably induces a lot of unnecessary backtracking. I'm also nervous that whites//0 from dcg/basics is deterministic; however, that part of the equation seems to work, it's just integrating it with the comment skipping that doesn't seem to.
As a final note, I don't see how to handle propagating parse errors back to the user with line/column information from here. It feels like I'd have to track and thread through some kind of current line/column info and write it into the tokens and then maybe try to rebuild the line if I wanted to do something similar to how llvm does it. Is that fair or is there a "recommended practice" there?
The whole code can be found in this haste.
It currently still looks a bit strange (unreadableNamesLikeInJavaAnyone?), but in its core it is quite solid, so I have only a few comments about some aspects of the code and the questions:
Separating lexing from parsing makes perfect sense. It is also a perfectly acceptable solution to store line and column information along with each token, leaving tokens (for example) of the form l_c_t(Line,Column,Token) or Token-lc(Line,Column) for the parser to process.
Comments are always nasty, or should I say, often not-nesty? A useful pattern in DCGs is often to go for the longest match, which you are already using in some cases, but not yet for anything//0. So, reordering the two rules may help you to skip everything that is meant to be commented away.
Regarding the determinism: It is OK to commit to the first parse that matches, but do it only once, and resist the temptation to mess up the declarative grammar.
In DCGs, it is elegant to use | instead of ;.
tokenize//1? Come on! That's just tokens//1. It makes sense in all directions.
I have this code to support error reporting, that itself must be handled with care, sprinkling meaningful messages and 'skip rules' around the code. But there is not ready-to-use alternative: a DCG is a nice computation engine, but it cannot compete out-of-the-box with specialized parsing engines, that are able to emit error messages automatically, exploiting the theoretical properties of the targeted grammars...
:- dynamic text_length/1.
parse_conf_cs(Cs, AST) :-
length(Cs, TL),
retractall(text_length(_)),
assert(text_length(TL)),
phrase(cfg(AST), Cs).
....
%% tag(?T, -X, -Y)// is det.
%
% Start/Stop tokens for XML like entries.
% Maybe this should restrict somewhat the allowed text.
%
tag(T, X, Y) -->
pos(X), unquoted(T), pos(Y).
....
%% pos(-C, +P, -P) is det.
%
% capture offset from end of stream
%
pos(C, P, P) :- text_length(L), length(P, Q), C is L - Q.
tag//3 is just an example usage, in this parser I'm building an editable AST, so I store the positions to be able to properly attribute each nested part in an editor...
edit
a small enhancement for id//1: SWI-Prolog has specialized code_type/2 for that:
1 ?- code_type(0'a, csymf).
true.
2 ?- code_type(0'1, csymf).
false.
so (glossing over literal transformation)
id([C|Cs]) --> [C], {code_type(C, csymf)}, id_rest(Cs).
id_rest([C|Cs]) --> [C], {code_type(C, csym)}, id_rest(Cs).
id_rest([]) --> [].
depending on your attitude to generalize small snippets, and the actual grammar details, id_rest//1 could be written in reusable fashion, and made deterministic
id([C|Cs]) --> [C], {code_type(C, csymf)}, codes(csym, Cs).
% greedy and deterministic
codes(Kind, [C|Cs]) --> [C], {code_type(C, Kind)}, !, codes(Kind, Cs).
codes(Kind, []), [C] --> [C], {\+code_type(C, Kind)}, !.
codes(_, []) --> [].
this stricter definition of id//1 would also allow to remove some ambiguity wrt identifiers with keyword prefix: recoding keyword//1 like
keyword(K) --> id(id(K)), {memberchk(K, [
array,
break,
...
]}.
will correctly identify
?- phrase(tokenize(Ts), `if1*2`).
Ts = [id(if1), *, int(2)] ;
Your string//1 (OT: what unfortunate clash with library(dcg/basics):string//1) is an easy candidate for implementing a simple 'error recovery strategy':
stringChar(0'\") --> "\\\\".
stringChar(0'") --> pos(X), "\n", {format('unclosed string at ~d~n', [X])}.
It's an example of 'report error and insert missing token', so the parsing can go on...
In the following tutorial: http://www.csupomona.edu/~jrfisher/www/prolog_tutorial/7_3.html
There is the part:
test_parser :- repeat,
write('?? '),
read_line(X),
( c(F,X,[]) | q(F,X,[]) ),
nl, write(X), nl, write(F), nl, fail.
Now I'm extremely confused about the c(F,X,[]) and q(F,X,[]) part because it doesn't seem to match any thing that I have seen, c only takes one parameter from what I can tell and these parameters don't seem to make sense for q. Please help me understand what is going on here.
c//1 and q//1 are entry points (aka top level production) of the Definite Clauses Grammar defined below, where you find
c(F) --> ....
q(F) --> ....
This style of 'call' on a DCG entry point is discouraged, usually is better to invoke the phrase(Grammar, TextToAnalyze, TextAfterAnalysis), in this case phrase((c(F) ; q(F)), "some text", "")...
The --> operator is usually rewritten adding 2 arguments, that are cause of your concern.
EDIT
I.e.
c(L) --> lead_in,arrange(L),end.
is rewritten to
c(L,X,Y) :- lead_in(X,X1),arrange(L,X1,X2),end(X2,Y).
c is defined with -->, which actually adds two hidden arguments to it. The first of these is a list to be parsed by the grammar rule; the second is "what's left" after the parse. c(F,X,[]) calls c on the list X to obtain a result F, expecting [] to be left, i.e. the parser should consume the entire list X.