How to use normal clauses converted from DCG Prolog one? - prolog

I know DCG is only a syntactic sugar , as prolog translate them in normal Clauses.
So, for instance,
palindrome --> [].
palindrome --> [_].
palindrome --> [X], palindrome, [X].
/* it is translated into: */
palindrome(A, A).
palindrome([_|A], A).
palindrome([X|A], B) :- palindrome(A, C), C=[X|B].
My problem is, I want to avoid, to use the "phrase" clause, and accessing the normal code converting fron the DCG one.
If I try to ask for a palindrome sequence, it simply dosen't work.
For istance:
? palindrome([1,2],X).
X = [1, 2] .
I'd like to have the same result as:
?- phrase(palindrome,[1,2,1]).
true
?- phrase(palindrome,[1,2,X]).
X = 1
Without using phrase.
Thanks

Related

Pattern matching with lists and strings with Prolog

a prolog newby here.
I found the following code online:
string_to_list_of_characters(String, Characters) :-
name(String, Xs),
maplist( number_to_character,
Xs, Characters ).
number_to_character(Number, Character) :-
name(Character, [Number]).
I want to use it to do some pattern matching.
This is what I have tried so far:
wordH1(H1) :-
word(H1),
string_length(H1,6),
string_to_list_of_characters(H1, X) = a,_,_,_,_,_.
I want to get all strings which are of length 6 and that start with an a.
You seem to be using some very old learning resource. Instead of writing this string_to_list_of_characters predicate yourself you can just use the builtin atom_chars:
?- atom_chars(apple, Chars).
Chars = [a, p, p, l, e].
?- atom_chars(amazon, Chars).
Chars = [a, m, a, z, o, n].
For pattern matching you can write lists similarly to how you tried to do it, but you need square brackets around the elements. You also don't pattern match on something like a "function application expression" as you would in other programming languages. Rather you apply a predicate and then write a separate unification. So it's not something like atom_chars(A, B) = Something but rather:
?- atom_chars(apple, Chars), Chars = [a,_,_,_,_,_].
false.
?- atom_chars(amazon, Chars), Chars = [a,_,_,_,_,_].
Chars = [a, m, a, z, o, n].

How do you join characters in a list together in Prolog?

Eg: ["c","h","a","r"] should print "char".
its atomic_list_concat(), but how would I do it for eg:
longest_common_prefix([H1,H2|T], P) :-
maplist(append(P), L, [H1,H2|T]).
Using library(double_quotes) as described here, we can use append/2 (note the 2!) :
?- set_prolog_flag(double_quotes).
true.
?- append(["c","h","a","r"], Cs).
Cs = "char".
However, please note that "c" is not a character! It is a list with one character. One single character is c alone. And most of the times, you do not need to write "c"
?- [c,h,a,r] = "char".
true.
in SWI-Prolog
?- atomic_list_concat( ["c","h","a","r"] , L).
L = char.
but things become hairier soon... you should take the time to learn about elementary data representation for anything serious

How palindrome check in prolog works? [duplicate]

Can I get a recursive Prolog predicate having two arguments, called reverse, which returns the inverse of a list:
Sample query and expected result:
?- reverse([a,b,c], L).
L = [c,b,a].
A recursive Prolog predicate of two arguments called palindrome which returns true if the given list is palindrome.
Sample query with expected result:
?- palindrome([a,b,c]).
false.
?- palindrome([b,a,c,a,b]).
true.
Ad 1: It is impossible to define reverse/2 as a (directly edit thx to #repeat: tail) recursive predicate - unless you permit an auxiliary predicate.
Ad 2:
palindrome(X) :- reverse(X,X).
But the easiest way is to define such predicates with DCGs:
iseq([]) --> [].
iseq([E|Es]) --> iseq(Es), [E].
reverse(Xs, Ys) :-
phrase(iseq(Xs), Ys).
palindrome(Xs) :-
phrase(palindrome, Xs).
palindrome --> [].
palindrome --> [E].
palindrome --> [E], palindrome, [E].
There isn't an efficient way to define reverse/2 with a single recursive definition without using some auxiliary predicate. However, if this is nevertheless permitted, a simple solution which doesn't rely on any built-ins like append/3 (and should be applicable for most Prolog implementations) would be to use an accumulator list, as follows:
rev([],[]).
rev([X|Xs], R) :-
rev_acc(Xs, [X], R).
rev_acc([], R, R).
rev_acc([X|Xs], Acc, R) :-
rev_acc(Xs, [X|Acc], R).
rev/2 is the reversal predicate which simply 'delegates' to (or, wraps) the accumulator-based version called rev-acc/2, which recursively adds elements of the input list into an accumulator in reverse order.
Running this:
?- rev([1,3,2,x,4],L).
L = [4, x, 2, 3, 1].
And indeed as #false has already pointed out (+1),
palindrome(X) :- rev(X,X).
Just for curiosity here goes a recursive implementation of reverse/2 that does not use auxiliary predicates and still reverses the list. You might consider it cheating as it uses reverse/2 using lists and the structure -/2 as arguments.
reverse([], []):-!.
reverse([], R-R).
reverse(R-[], R):-!.
reverse(R-NR, R-NR).
reverse([Head|Tail], Reversed):-
reverse(Tail, R-[Head|NR]),
reverse(R-NR, Reversed).
conca([],L,L).
conca([X|L1],L2,[X|L3]):- conca(L1,L2,L3).
rev([],[]).
rev([X|Y],N):- rev(Y,N1),conca(N1,[X],N).
palindrome([X|Y]):- rev([X|Y],N),equal([X|Y],N).
equal([X],[X]).
equal([X|Y],[X|Z]):- equal(Y,Z).

How to deconstruct a compound term in SWI Prolog

I have compound terms that can have a number inside the braces.
For example: qpowieipq(5),lsjdlasa(15) or lkjlk. I got it from the database (like my_list([rxclk,rxer,rxdv,rxd(0),rxd(1),rxd(2),crs,col,txen,txd(0),txd(1),txd(2),‌​txd(3)]).).
How can I get the value of the number inside the braces?
For example:
my_function(qpowieipq(5), X).
X=5.
my_function(lsjdlasa(15), X).
X=15.
my_function(lkjlk, X).
false
I am using SWI Prolog.
You can use (=..)/2 and pattern matching to deconstruct Prolog's compound terms. For instance
?- a =.. X.
X = [a].
?- a(1) =.. X.
X = [a, 1].
So, tentatively
my_function(T, V) :- T =.. [_,V], number(V).
This will work with any ISO compliant Prolog processor.

How to write optional in SWI-Prolog

I need to implement some rules by Prolog
ex:
S ---> A,[b],{c}.
Where:
[b] could happen once or none like 0 or 1 time
{c} could happen 0,1,2,...times
How can i write it?
Edit:
I used this:
:- op(700,xfx,--->).
s ---> [vp].
s ---> [vp,conj,vp].
s ---> [vp,conj,np].
vp ---> [feal_amr],
([mfoal_beh];[]),
([mfoal_beh];[]),
([bdl];[]),
[sefa_optional],
([hal];[]),
([shbh_gomla];[]),
([mfoal_motlk];[]).
It gives me an error "Full stop in clause-body? Cannot redefine ,/2"
in the comma in this line "vp ---> [feal_amr], ..."
Edit
I use "--->" because i have this
parse_topdown(Category,String,Reststring,[Category|Subtrees]) :-
Category ---> RHS,
matches(RHS,String,Reststring,Subtrees).
And "-->" gives an error with the operator ":-"?!!
this is my code for an Arabic Parser Code
I'm sorry for inconvenience but i am not an expert in Prolog
from your description
s --> [a], ([b] ; []), c_1.
c_1 --> [c], c_1 ; [].
some test pattern:
?- phrase(s, [a,b,c,c,c]).
true
?- phrase(s, [a]).
true
edit
about your code: you should use -->. Why you declare ---> (and not define it) ? That way you should write your own analyzer, you're not using DCG.
Note that [vp,conj,vp] it's a list of terminals,
Not sure about feal_amr,mfoal_beh, etc etc, but vp it's surely a nonterminal (it's rewritten).
Then I think you should write
s --> vp.
s --> vp,conj,vp.
s --> vp,conj,np.
vp -->
[feal_amr],
([mfoal_beh];[]),
([mfoal_beh];[]),
([bdl];[]),
[sefa_optional],
([hal];[]),
([shbh_gomla];[]),
([mfoal_motlk];[]).
% I hypotesize it's a comma.
conj --> [','].
edit as noted in comments, you are not using DCG, but your own interpreter. I tested it with a minimal example
:- op(700,xfx,--->).
s ---> [name,verb,names].
names ---> [name, conj, names].
names ---> [name].
names ---> [].
lex(anne, name).
lex(bob, name).
lex(charlie, name).
lex(call, verb).
lex(and, conj).
parse_topdown(Category,[Word|Reststring],Reststring,[Category,Word]) :-
lex(Word,Category).
parse_topdown(Category,String,Reststring,[Category|Subtrees]) :-
Category ---> RHS,
matches(RHS,String,Reststring,Subtrees).
matches([],String,String,[]).
matches([Category|Categories],String,RestString,[Subtree|Subtrees]) :-
parse_topdown(Category,String,String1,Subtree),
matches(Categories,String1,RestString,Subtrees).
and this program accepts 0,1, or more names:
?- parse_topdown(s,[anne,call,bob,and,charlie],R,P).
R = [],
P = [s, [name, anne], [verb, call], [names, [name, bob], [conj, and], [names|...]]] ;
R = [charlie],
P = [s, [name, anne], [verb, call], [names, [name, bob], [conj, and], [names]]] ;
R = [and, charlie],
P = [s, [name, anne], [verb, call], [names, [name, bob]]] ;
R = [bob, and, charlie],
P = [s, [name, anne], [verb, call], [names]] ;
false.
Note I leave R free, to examine partial matches. Coming back to your original question, you can see how the nonterminal names accepts 0,1,or many (separed by and) values.
Note that such interpreter will be very slow on any substantial input. I'd advise you to rewrite your grammar using DCG.
First, you probably want to lower-case S and A; Prolog uses initial caps for variable names.
One way to allow 'b' to occur once or not at all is to write something like this:
s --> a, b_optional, {c}.
b_optional --> [b].
b_optional --> [].
There is also syntax for writing the two rules for b_optional as a single rule, if you prefer; consult the chapter on definite clause grammars in your favorite Prolog text.
I don't know what you mean by c happening 0, 1, 2, ... times, so I don't think I can help you there.

Resources