How to write optional in SWI-Prolog - 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.

Related

How to use normal clauses converted from DCG Prolog one?

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

How to define a string concatenation operator in prolog?

I am manipulating strings of characters in prolog, and I would like to avoid the use of too many temporary variables in my rules.
I would like to transform something like this:
process_str(Str, Next) :-
is_valid_pattern0(Pattern0),
concat(Pattern0, Tail0, Str),
concat("->", Tail1, Tail0),
is_valid_pattern1(Pattern1),
concat(Pattern1, Tail2, Tail1),
concat("|", Tail2, Next).
using a concatenation operator definition, into something like:
process_str(Pattern0.."->"..Pattern1.."|"..Next, Next) :-
is_valid_pattern0(Pattern0),
is_valid_pattern1(Pattern1).
which I believe would be far more readable, at the expense of a few more operations depending on how the operator is defined.
I found that the documentation talks about defining operators, but as far as I understand, one can only define predicate operators, not functional operators that can "return a value" (like for instance the + operator).
Please tell me either why I am wrong or how to define such a concatenation operator.
Here's a solution using DCG and term_expansion that works in SWI-Prolog. First, the basics:
:- set_prolog_flag(double_quotes, chars).
This ensures that "foo" will be interpreted as a list of three characters, not some non-standard atomic "string" object.
Then, let's assume that valid pattern0 and pattern1 matches are simply lists of letters. It's up to you to fill in the details. Some basic DCGs:
letters -->
[].
letters -->
[Letter],
{ char_type(Letter, alpha) },
letters.
pattern0 -->
letters.
pattern1 -->
letters.
For example:
?- phrase(pattern0, Pattern0).
Pattern0 = [] ;
Pattern0 = ['A'] ;
Pattern0 = ['A', 'A'] ;
Pattern0 = ['A', 'A', 'A'] ;
Pattern0 = ['A', 'A', 'A', 'A'] ;
Pattern0 = ['A', 'A', 'A', 'A', 'A'] .
?- phrase(pattern0, "helloworld").
true.
Also, the handy DCG describing simply a list:
list([]) -->
[].
list([X | Xs]) -->
[X],
list(Xs).
This doesn't seem to do much, but it will come in handy in a moment:
?- phrase(list([a, b, c]), List).
List = [a, b, c].
?- phrase(list(List), [a, b, c]).
List = [a, b, c] ;
false.
Now, you would like to define a composite pattern like Pattern0.."->"..Pattern1.."|"..Next. I suggest to write this a bit differently, namely as a list of sub-patterns: [pattern0, "->", pattern1, "|", Next]. Such a list may contain three kinds of elements:
DCG rule names
literal lists of characters
variables that may become bound to lists of characters
We can then write a DCG matching some composite patterns:
composite([]) -->
[].
composite([Head | Tail]) -->
{ atom(Head) },
% Assume that this atom is the name of another DCG rule, and execute it.
call(Head),
composite(Tail).
composite([Head | Tail]) -->
list(Head),
composite(Tail).
This expresses that a composite pattern just describes a sequence of whatever its sub-patterns describe. It only has two clauses dealing with sub-patterns: One for DCG rule names (represented by atoms) and one for character lists. The case of variables is handled automatically by the character list clause!
We can use this definition to match a character list like "foo->bar|baz" against a composite pattern:
?- phrase(composite([pattern0, "->", pattern1, "|", Next]), "foo->bar|baz").
Next = [b, a, z] ;
false.
Almost done! We can pack this up in a definition encapsulating the pattern:
process_str(Sequence, Next) :-
phrase(composite([pattern0, "->", pattern1, "|", Next]), Sequence).
This works like this:
?- process_str("foo->bar|baz", Next).
Next = [b, a, z] ;
false.
I think this is already pretty good. But if you really want a kind of pattern matching syntax, term_expansion will help. Its use is (deceptively) simple: Define a clause for term_expansion(SomeTermPattern, SomeOtherTerm), and every clause definition matching SomeTermPattern will be treated as if the programmer had written SomeOtherTerm instead. So:
term_expansion(
% Replace every definition of this form:
patterned_process_str(Pattern, Next),
% by a replacement like this:
patterned_process_str(Sequence, Next) :-
phrase(composite(Pattern), Sequence)
).
patterned_process_str([pattern0, "->", pattern1, "|", Next], Next).
We can look at Prolog's internal representation of the source code for patterned_process_str to make sure that it is as expected:
?- listing(patterned_process_str).
patterned_process_str(B, A) :-
phrase(composite([pattern0, [-, >], pattern1, ['|'], A]), B).
Variable names are lost, but otherwise our definition for patterned_process_str was expanded to the form we wanted, namely the same form that we wrote for process_str above. This definition works exactly like process_str above (since it is equivalent):
?- patterned_process_str("foo->bar|baz", Next).
Next = [b, a, z] ;
false.
Exercise: Provide an operator definition for ... Write a predicate pattern_list that converts between "dotted patterns" with .. and "list patterns", for example: pattern_list(A..B..C, [A, B, C]) should succeed. Then, expand the above term_expansion rule in a way that allows you to write patterned_process_str using the "dotted pattern" syntax directly.
You could define in your ~/.swiplrc the following pair of operators:
:- op(699,xfx,:=). % just below =
:- op(698,yfx,++). % just below :=
Out := Left ++ Right :-
flatten_expr_to_string(Left,LStrings),
flatten_expr_to_string(Right,RStrings),
atomics_to_string([LStrings,RStrings],Out).
flatten_expr_to_string(A++B,String) :-
String := A ++ B.
flatten_expr_to_string(Term,String) :-
maplist(integer,Term)
-> string_codes(String,Term)
; term_string(Term,String).
and then
?- X:=`foo`++bar++help.
X = "foobarhelp" .
?- X:=`foo`++123+bar++help.
X = "foo123+barhelp" .
Note that there is an ambiguity about lists of integers (as a backtick string is just that...). Hope you can live with that...
If you use the XPCE editor, just pull the menu [Edit \ Prolog preferences] and add the snippet there, then recompile (Ctrl+b). This will works also on Windows also, where ~/.swiplrc is named in another manner, more appropriate for the platform.
When you have defined an appropriate mini language for your strings expressions, you can explore term rewriting, to enable passing expressions to your predicates, without introducing new variables. Beware that's rather difficult to debug... you can analyze lifter in this repo to get some hints

Find an "infix" of a list in Prolog - order matters

A question from someone who knows Prolog for a week=)
I am writing some prolog command infix(Inf,List)
to check if one list is, as our prof formulated, "an infix" of another list. The order matters+ it shouldn't be right at the beginning or the end of the List.
That means for example:
If we have Inf=[1,2] and List=[1,2,3,4] then is is false.
If we have Inf=[3,4] and List=[1,2,3,4] then is is also false.
If we have Inf=[2,3] and List=[1,2,3,4] then it is true.
If it is Inf=[3,2] and List=[1,2,3,4] then is is false.
If it is Inf=[2,4] and List=[1,2,3,4,5] then is is false.
I wrote some rules already and with them I seem to manage to solve the problem of order and not counting the first element of a List.
infix(Inf,List):- length(Inf,L1),length(List,L2), L1>L2, !, fail.
infix(Inf,List):- length(Inf,L1),length(List,L2), L1=L2, !, fail.
infix(Inf,List):- length(Inf,L1),length(List,L2), L1<L2, delete_first(Inf,List).
delete_first(Inf,[_L|List]):- sublist(Inf,List).
sublist([El|Sub],[El|List]):- checksublist(Sub,List).
sublist([S|Sub],[L|List]):- sublist([S|Sub],List).
checksublist([], L).
checksublist([El|Sub],[El|List]):- checksublist(Sub,List).
However, I can't formulate it in a way, so that the last element is not counted =(. According to my intuitive logic the conditionchecksublist([], L).should be smth like checksublist([], [_|[]]). But it doesn't work this way- I get false for everything.
Does anybody know how to get rid of the last element in this situation? Thanks in advance!
Grammars to the rescue! But I would not call this infix. It's a certain subsequence, actually even a certain substring.
infix(Inf, List) :-
Inf = [_|_],
phrase(([_], ..., seq(Inf), [_], ...), List).
% The following are frequently predefined
... --> [] | [_], ... .
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
(Edit) Since you insist that both the prefix and the postfix are non-empty, you probably want this to hold for the infix too. Thus Inf = [_|_] added.
This is the result using Scryer's top level:
?- infix(Inf,"abcdef").
Inf = "b"
; Inf = "bc"
; Inf = "bcd"
; Inf = "bcde"
; Inf = "c"
; Inf = "cd"
; Inf = "cde"
; Inf = "d"
; Inf = "de"
; Inf = "e"
; false.
See this how to print lists of characters as double quoted chars in other systems.
This is too imperative.
You can let Prolog solve it with append/2. It's search-assisted programming, let's use it.
infix(Inf,List) :- append([Prefix,Inf,Suffix],List),Prefix\=[],Suffix\=[].
This is completely declarative, in the sense that
it is formulated as constraint that a solution must fulfill (very mathematical).
Test it using the Unit Test framework:
:- begin_tests(infix).
test(one,[fail]) :- infix([1,2],[1,2,3,4]).
test(two,[fail]) :- infix([3,4],[1,2,3,4]).
test(three) :- infix([2,3],[1,2,3,4]).
test(four,[fail]) :- infix([3,2],[1,2,3,4]).
test(five,[fail]) :- infix([2,4],[1,2,3,4,5]).
:- end_tests(infix).
rt:-run_tests(infix).
Then
?- rt.
% PL-Unit: infix ..
Warning: user://1:12:
PL-Unit: Test three: Test succeeded with choicepoint
.. done
% All 5 tests passed
true.
Sadly, Prolog does not do deep reasoning and theorem proving but employs brute force: it tries possible solutions until one passes or there are no more. Weel, it's sufficient for this case.
For example:
?- append([Prefix,[3,4],Suffix],[1,2,3,4,5,3,4,6]).
Prefix = [1, 2],
Suffix = [5, 3, 4, 6] ;
Prefix = [1, 2, 3, 4, 5],
Suffix = [6] ;
false.

In Prolog DCGs, how to remove over general solutions?

I have a text file containing a sequence. For example:
GGGGGGGGAACCCCCCCCCCTTGGGGGGGGGGGGGGGGAACCCCCCCCCCTTGGGGGGGG
I have wrote the following DCG to find the sequence between AA and TT.
:- use_module(library(pio)).
:- use_module(library(dcg/basics)).
:- portray_text(true).
process(Xs) :- phrase_from_file(find(Xs), 'string.txt').
anyseq([]) -->[].
anyseq([E|Es]) --> [E], anyseq(Es).
begin --> "AA".
end -->"TT".
find(Seq) -->
anyseq(_),begin,anyseq(Seq),end, anyseq(_).
I query and I get:
?- process(Xs).
Xs = "CCCCCCCCCC" ;
Xs = "CCCCCCCCCCTTGGGGGGGGGGGGG...CCCCC" ;
Xs = "CCCCCCCCCC" ;
false.
But I dont want it to find the second solution or ones like it. Only the solutions between one pair of AA and TTs not all combinations. I have a feeling I could use string_without and string in library dcg basiscs but I dont understand how to use them.
your anyseq//1 is identical to string//1 from library(dcg/basics), and shares the same 'problem'.
To keep in control, I would introduce a 'between separators' state:
elem(E) --> begin, string(E), end, !.
begin --> "AA".
end -->"TT".
find(Seq) -->
anyseq(_),elem(Seq).
anyseq([]) -->[].
anyseq([E|Es]) --> [E], anyseq(Es).
process(Xs) :-
phrase(find(Xs), `GGGGGGGGAACCCCCCCCCCTTGGGGGGGGGGGGGGGGAACCCCC+++CCCCCTTGGGGGGGG`,_).
now I get
?- process(X).
X = "CCCCCCCCCC" ;
X = "CCCCC+++CCCCC" ;
false.
note the anonymous var as last argument of phrase/3: it's needed to suit the change in 'control flow' induced by the more strict pattern used: elem//1 is not followed by anyseq//1, because any two sequences 'sharing' anyseq//1 would be problematic.
In the end, you should change your grammar to collect elem//1 with a right recursive grammar....
First, let me suggest that you most probably misrepresent the problem, at least if this is about mRNA-sequences. There, bases occur in triplets, or codons and the start is methionine or formlymethionine, but the end are three different triplets. So most probably you want to use such a representation.
The sequence in between might be defined using all_seq//2, if_/3, (=)/3:
mRNAseq(Cs) -->
[methionine],
all_seq(\C^maplist(dif(C),[amber,ochre,opal]), Cs),
( [amber] | [ochre] | [opal]).
or:
mRNAseq(Cs) -->
[methionine],
all_seq(list_without([amber,ochre,opal]), Cs),
( [amber] | [ochre] | [opal]).
list_without(Xs, E) :-
maplist(dif(E), Xs).
But back to your literal statement, and your question about declarative names. anyseq and seq mean essentially the same.
% :- set_prolog_flag(double_quotes, codes). % pick this
:- set_prolog_flag(double_quotes, chars). % or pick that
... --> [] | [_], ... .
seq([]) -->
[].
seq([E|Es]) -->
[E],
seq(Es).
mRNAcontent(Cs) -->
...,
"AA",
seq(Cs),
"TT",
{no_TT(Cs)}, % restriction
... .
no_TT([]).
no_TT([E|Es0]) :-
if([E] = "T",
( Es0 = [F|Es], dif([F],"T") ),
Es0 = Es),
no_TT(Es).
The meaning of no_TT/1 is: There is no sequence "TT" in the list, nor a "T" at then end. So no_TT("T") fails as well, for it might collide with the subsequent "TT"!
So why is it a good idea to use pure, monotonic definitions? You will most probably be tempted to add restrictions. In a pure monotonic form, restrictions are harmless. But in the procedural version suggested in another answer, you will get simply different results that are no restrictions at all.

How can I get the type of a term in SWI Prolog

Is there a way to know what type is a variable in Prolog?
I have the code
test:-
writeln('Please enter the absolut file name :'),
read(FileName),
write('Opening file '),
write(FileName),nl,
open(FileName,read,Stream),
read_file(Stream,Lines),
close(Stream),
parseLines(Lines).
% used on reading the text file
read_file(Stream,[]) :-
at_end_of_stream(Stream).
% used on reading the text file
read_file(Stream,[X|L]) :-
\+ at_end_of_stream(Stream),
read(Stream,X),
read_file(Stream,L).
parseLines(Lines):-
%primele 2 linii contin lista cu barbatii si list cu femeile iar
%restul liniilor contin preferintele acestora
Lines=[LB|[LF|LPrefs]],
writeln(LB),
atom_length(LB,2).
And I get the error (when running test)
ERROR: [Thread pdt_console_client_0_Default Process] atom_length/2: Type error: `list' expected, found `man([m1,m2])'
The input text file contains
man = {m1, m2}.
women = {w1, w2}.
m1: w1 > w2.
m2: w1 > w2.
w1: m1 > m2.
w2: m1 > m2.
I am trying to parse that file but anything I try I get that error, like the things in the Lines read from the file are not string,atoms , I have no idea what to do to fix this.
P.S.Any idea on how to fast/simple parse the file? It feels strange that parsing the input for the problem is much harder then solving the problem.
Thanks.
Edit: I found the compound predicate and the line read from files is a compound term.
Edit2:
My goal is to read the data in that file and assert it or similar, I want to solve the stable marriage problem, I solve it but I can't figure out this part of reading the input from this file format.
Edit3:
I have other input files that have lines like:
alan: christine > tina > zoe > ruth > sarah.
and this lines fail when trying to read them as terms with read_file_to_terms because of the multiple > operators, so I think not all my inputs are valid Prolog
Since you tagged your question [swi-prolog], and your file contains valid Prolog terms, you could use read_file_to_terms/3, and load the list in a single call (this hint is for P.S. part). After that you must process your terms' list: your parseLines/1 it's useless. Just as example of list processing, I'll display each loaded term:
?- read_file_to_terms('/home/carlo/x.txt',L,[]), maplist(writeln, L).
man={m1,m2}
women={w1,w2}
m1:w1>w2
m2:w1>w2
w1:m1>m2
w2:m1>m2
L = [man={m1, m2}, women={w1, w2}, m1:w1>w2, m2:w1>w2, w1:m1>m2, w2:m1>m2].
edit I think {} is named 'set constructor', it's just a weird shape for a compound:
?- write_canonical({a,b,c}).
{}(','(a,','(b,c)))
you can use univ to get the list of arguments
?- {a,b,c} =.. X.
X = [{}, (a, b, c)].
bug in previous edit
=.. seems of little relevance, because more than a compound, {} resembles an operator, both prefix and postfix (i.e. combining in some way op(xf,,({)) and op(fx,,(}))).
AFAIK converting 'the set' to a list requires something like
setcons_to_list(S, L) :-
S =.. [{}, E] -> andexpr_to_list(E, L) ; L = [].
andexpr_to_list((E,Es), [E|Ts]) :-
!, andexpr_to_list(Es, Ts).
andexpr_to_list(E, [E]).
test
?- setcons_to_list({},L).
L = [].
?- setcons_to_list({1,2,3,4},L).
L = [1, 2, 3, 4].
more edit
Prolog operators are 'configurable', it's possible to instruct the parser about that preference list. Add an op declaration in your source :- op(10,xfy,(>)).. Here a sample using the prompt
?- op(10,xfy,(>)).
true.
?- X = (alan: christine > tina > zoe > ruth > sarah),write_canonical(X).
:(alan,>(christine,>(tina,>(zoe,>(ruth,sarah)))))
X = alan:christine>tina>zoe>ruth>sarah.
beware: changing the predefined associativity should be done with care. Otherwise, this other answer could be useful if you prefer to craft a more general parser, using DCGs.

Resources