What does the operator `-->` in Prolog do? - prolog

What does the --> operator do in Prolog and what is the difference between it and :-?
I'm using SWI Prolog.

It is used to define a DCG (Definite Clause Grammar) rule as opposed to a normal predicate. See this tutorial for a very nice explanation of DCG rules.
There are many examples here on Stack Overflow. See the DCG tag.
Here is one very simple solution, showing both the DCG and the normal predicate.
Note that you have to use phrase/2 or phrase/3 to evaluate a DCG. Make sure to read the section of the SWI-Prolog manual on DCGs. The two phrase predicates are documented there.

The --> operator reads in Definite Clause Grammar rules. It's syntactic sugar to transform rules of the form:
parenthesized_expression(Inner) -->
[ open ],
expression(Inner),
[ close ],
{ nl }.
Into something more like this:
parenthesized_expression(Inner, [open | T1], T2) :-
expression(Inner, T1, [close | T2]),
nl.
This makes writing grammars very convenient. There are helper predicates available to consume them, though you're allowed to do so by hand if you prefer.

Related

DCG: hidden argument across all Rules?

.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.

current_predicate in SICStus Prolog

SICStus Prolog offers both current_predicate/1 and current_predicate/2.
The manual page states:
current_predicate(?PredSpec)
Unifies PredSpec with a predicate specifications of the form Name/Arity.
current_predicate(?Name, ?Term)
Unifies Name with the name of a user-defined predicate, and Term with the most general term corresponding to that predicate.
They appear to have the same features:
both predicates work for enumerating predicates, both work with modules.
The manual page comments:
current_predicate/1 is part of the ISO Prolog standard; current_predicate/2 is not.
Should I ever use current_predicate/2 in new (= non-legacy) code?
Short answer, no. Don't use it in new code.
The benefit of current_predicate/2 was to allow querying, using a predicate call template, if the predicate is defined, unlike current_predicate/1. E.g.
...,
( current_predicate(_, foo(_, _)) ->
foo(A, B)
; ...
),
...
But you can often use instead the standard predicate_property/2 predicate, which takes a template as first argument.
P.S. The Logtalk linter will scream at you (and suggest a more standard alternative) if it finds you calling current_predicate/2 :-)

Expanding DCGs in Prolog

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.

How to accept one of two configurations of predicate arguments

Say i have two variables A and B, and two predicates firstPred() and secondPred()
I'm trying to express something along the lines of:
(firstPred(A) && secondPred(B)) || (firstPred(B) && secondPred(A))
I currently have
firstPred(A),
secondPred(B).
but this only covers the first case. How can i add support for the second?
Reference to predicates in Prolog use the notation Name/Arity, where Arity is the number of arguments. Therefore, instead of writing firstPred() and secondPred(), write instead firstPred/1 and secondPred/1. Better yet, following Prolog coding guidelines, use underscores instead of CamelCase when naming predicate.
To answer your question, you need to define a predicate to check your condition. This predicate will take two arguments. A direct translation of your condition would be:
condition(A, B) :-
( first_predicate(A),
second_predicate(B)
; first_predicate(B),
second_predicate(A)
).
But this is not considered good style and it's preferable to use instead two clauses:
condition(A, B) :-
first_predicate(A),
second_predicate(B)
condition(A, B) :-
first_predicate(B),
second_predicate(A).
Note that this solution assumes that the disjunction in the condition is not an exclusive disjunction. Is that the case?

Ignore rest of input

What's the preferred way to ignore rest of input? I found one somewhat verbose way:
ignore_rest --> [].
ignore_rest --> [_|_].
And it works:
?- phrase(ignore_rest, "foo schmoo").
true ;
But when I try to collapse these two rules into:
ignore_rest2 --> _.
Then it doesn't:
?- phrase(ignore_rest2, "foo schmoo").
ERROR: phrase/3: Arguments are not sufficiently instantiated
What you want is to state that there is a sequence of arbitrarily many characters. The easiest way to describe this is:
... -->
[].
... -->
[_],
... .
Using [_|_] as a non-terminal as you did, is an SWI-Prolog specific extension which is highly problematic. In fact, in the past, there were several different extensions to/interpretations of [_|_]. Most notably Quintus Prolog did permit to define a user-defined '.'/4 to be called when [_|_] was used as a non-terminal. Note that [_|[]] was still considered a terminal! Actually, this was rather an implementation error. But nevertheless, it was exploited. See for such an example:
David B. Searls, Investigating the Linguistics of DNA with Definite Clause Grammars. NACLP 1989.
Why not simply use phrase/3 instead of phrase/2? For example, assuming that you have a prefix//0 non-terminal that consumes only part of the input:
?- phrase(prefix, Input, _).
The third argument of phrase/3 returns the non-consumed terminals, which you can simply ignore.

Resources