Prolog: declaring an operator - prolog

I have defined ! (factorial) function and registered it as arithmetic function and an operator, so that I can execute: A is 6!.
Now I'd like to define !! (factorial of odd numbers), but the same way - writing clauses, registering arithmetic_function and operator, calling A is 7!! - results in
SyntaxError: Operator expected
How should I, if possible, register !! operator ?
Yes, I realize, ! is normally the cut.

! is a so-called solo character, you cannot have two in a row. If it were not, you could not write for example:
c :- !.
but would instead have to write:
c :- ! .
because "!." would otherwise be interpreted as a single token.
Also, if you let ! be an operator, both versions are invalid syntax (yes, SWI still accepts it, but for example GNU Prolog does not). You need to write:
c :- (!).
because operators that are operands need to be bracketed. Instead of !, use for example "f" and "ff", or fitting Unicode characters for your use case.

Related

converting character list to list of strings with each one contains 3 characters in Prolog

I want to convert list of character to list of strings with each one contains 3 characters using Prolog.
For example, ['a','b','c','d','e','f'] will be converted to ["abc", "def"].
What I tried was
toTriplets([H1|[H2|[H3|T]]],[F|R]) :- string_concat(H1,H2,X) , string_concat(X,H3,F) , toTriplets(T,R).
However, this gives me false when I execute the command
?- toTriplets(['a','b','c','d','e','f'],X).
false.
What is the problem with my code? I really can't figure it out...
The problem is you're missing the base case of recursion.
For instance
toTriplets([],[]).
Indeed there you have the chance to decide if accept only triples - as above - or accept also incomplete ones, like
toTriplets([A,B],[AB]) :- string_concat(A,B,AB).
toTriplets([A],[S]) :- atom_string(A,S).

Creating a if else in prolog

I'm trying to create a if/else verification in prolog, but actually i cant pass a parenthesis as a predicate "parameter", the code follows bellow
s(Z):- si(X), vp(Y), append(X,Y,Z).
si(Z):- i(X), openParent(Y), append(X,Y,Z).
vp(Z):- cond(X), closeParent(Y), append(X,Y,Z).
i([if]).
openParent(['(']).
closeParent([')']).
cond([cond]).
%running s(X) to see all the possibilities:
%expected : if, (, cond, )
%output : if, '(', cond, ')'
On openParent and closeParent i want to pass the parenthesis without quotes, but if do, the execution gives an error.
Prolog constants start with lower case letters, if you want to have constants that do not follow this convention you have to escape them via '('. To distinguish them from the reserved keywords the escaping needs to stay in place. This is still better than C for example, where int void = 0 is a forbidden statement and there's no escaping to write it down.
You might also want to think about what your predicate is supposed to do. A unary predicate like s/1 can only tell you if the term you pass fulfils your requirements. If you want to create something out of it (for example an evaluation of the if-then-else) you would need two arguments s(Ast, Evaluation).
Another observation is that you are already working on a symbolic representation: your code produces e.g. a list [if, '(', Cond, ')', TrueBranch] where if only takes one space (a string would use two). But if the representation is symbolic, why not just represent parenthesis as lparen and rparen? Or even better, if has only two / three arguments, why not represent it as if(Cond, TrueBranch) and if(Cond, TrueBranch, ElseBranch)?

How to get SWI-Prolog to always print strings with quotes, in interactive mode

When using SWI-prolog, it will print output that doesn't need to be quoted (output that doesn't contain special characters), without quotes.
As an example:
?- p('this_is_a_string').
true.
?- p(X).
X = this_is_a_string.
I would like Prolog to always output with quotes. It is okay if my output ends up quoting stuff like functor names, which were not originally quoted when input. How can I achieve this?
To change the default behaviour of SWI-Prolog's top-level output, you want to look towards setting a flag. If you query the appropriate flag, you should find this is your default output:
?- current_prolog_flag(print_write_options, Options).
Options = [portray('true'), quoted('true'), numbervars('true')].
In this particular case, the needed flag is already set: we have portray('true') in our Options.
portray/1 is a dynamic predicate that you can assert. It's called with a ground term when it is being printed, if it succeeds then it's assumed the the term has been printed.
So in your case you can assert the following:
portray(Term) :- atom(Term), format("'~s'", Term).
Now you'll get the desired behaviour:
?- p(this_is_an_atom).
true.
?- p(X).
X = 'this_is_an_atom'.
You could add this to your .swiplrc file if it's something you want all the time. Note, this will have no effect on write/1 and similar predicates, you'll need to use this instead:
?- write_term(foo, [portray(true)]).
'foo'.
To add the additional requirement of escaping characters in the the atom, you'll either need to implement your own DCG to the ISO standard for escaping characters, or abuse the built-in one. To do this you can write out to an atom and see if you need to add your single-quotes, or if they would already be there. The case of X = (\). is most easily handled in its own clause, you can then choose if you wish to print '\\' or (\).
portray(\) :-
format("'\\\\'"), !.
portray(Term) :-
atom(Term), \+ Term = (\),
( with_output_to(chars(['\''|_]),
write_term(Term, [quoted(true), character_escapes(true), portrayed(false)]))
-> format("~q", Term)
; format("'~s'", Term)
).

How to check that a string contains only certain characters in Prolog?

I want to write a predicate containsOnly(X,Y), which returns true, if string X contains only characters from string Y.
I wrote it this way:
containsOnly([],_).
containsOnly([H|T],AcceptableCharacters) :-
member(H, AcceptableCharacters),
containsOnly(T,AcceptableCharacters).
But the queries below return false. How can I modify the predicate in order for them to return true?
containsOnly('A', 'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜabcdefghijklmnopqrstuvwxyzäöüАБВГДЕЁЖЗИКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзиклмнопрстуфхцчшщъыьэюя-').
containsOnly('a', 'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜabcdefghijklmnopqrstuvwxyzäöüАБВГДЕЁЖЗИКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзиклмнопрстуфхцчшщъыьэюя-').
working with atoms, as in your question, an ISO compliant solution:
containsOnly(X,Y) :- forall(sub_atom(X,_,1,_,C), sub_atom(Y,_,1,_,C)).
while SWI-Prolog ver. >= 7 seems to accept it for 'strings' also.
Your problem is the datatype. You use atoms, but you treat them as char/code lists. You can try use double quotes " instead of single quotes ' and see if this helps.
With SWI-Prolog 7 or later, it won't help. You would have to use backticks instead of double quotes.
You really should figure out the documentation and the datatypes though.
This is a list of codes in SWI-Prolog 7:
`абвгд`
And 0'x is Prolog notation for character codes:
?- X = 0'г.
X = 1075.
?- X = `абв`.
X = [1072, 1073, 1074].
Another thing: if you are using SWI-Prolog, you should use memberchk/2 instead of member/2 in this particular case. If this is an efficiency bottleneck, however, you might also consider using the method described at the very bottom of this page. (This whole section of the manual is very important if you are going to be dealing with text in your SWI-Prolog program.)

Prolog reassigning operators

I'm new to prolog and I'm trying to reassign operators in prolog by changing their precedence. I'm running into 4 errors for the following:
:-op(1000,yf,+). %unary plus%
:-op(1000,yf,-). %unary minus%
:-op(750,yfx,"%"). %modulo%
The first two give me a similar error that goes like this:
warning: directive failed (op(1000,xf,+)) with exception (error(permission_error(create,operator,+),op/3))
I also get an error with the modulo one (a different error), but I suspect it's because I'm not supposed to enclose % in quotes (but how am I supposed to differentiate it from a comment marker?).
I've redefined a bunch of other operators (such as the addition operator :-op(500,yfx,+).) and they give me no problems. Only the 3 listed above give me errors.
Can anyone shed some light on this?
Thanks!
GNU Prolog documentation states that
An atom can have multiple operator definitions (e.g. prefix and infix like +) however an atom cannot have both an infix and a postfix operator definitions.
from here the errors on first two declaration. Then you should change the specifier to fy.
The modulo operator will need single quotes around.
You are attempting to define + as a postfix operator. However, + is also defined as an infix operator and the standard does not permit to define an operator both as postfix and infix. If you really want to do this you have to first undefine the infix operator using priority 0.
However, I can only recommend that you do not change standard operators like + or -. It's like you would change the operator precedence in C, C++, C#, Java, Perl, PHP, Javascript and the like: It would make your life as a programmer very, very miserable.
I cannot recommend to use % as operator in Prolog: % starts a comment. If you want to use it as an operator, you would have to write '%' quoted all the time. Prolog has already mod and rem defined as operators. Isn't that enough?
You are probably using GNU Prolog which is quite ISO conforming. Other Prologs permit you to define infix and postfix at the same time. See #237. But those other Prologs do a lot of things differently.
As a general remark: As a beginner, better stay away from changing the operator table. You really need to get used to the standard operators first. And with more experience you will most probably prefer to only add new operators with similar precedence than existing ones.
iso-prolog: ISO/IEC 13211-1:1995 6.3.4.3 Operators, last paragraph:
There shall not be an infix and a postfix operator with thesame name.

Resources