Prolog Syntax Issue - Variable Functor - prolog

I've been trying to use this code for a while now and it says there is a syntax error but I'm not sure what it is.
studies(ahmed,history(77,63)).
studies(john,chemistry(0,21)).
passed(Person,Subj):-
studies(Person, Subj(Work, Exam)),
Final is Work + Exam,
Final >=60.

You can't directly "parameterize" the functor, but you can use the =../2 operator, which unifies a functor and arguments with a list:
passed(Person, Subj):-
studies(Person, SubjWorkExam),
SubjWorkExam =.. [Subj, Work, Exam],
Work + Exam >= 60.
This avoids hard-coding the various subjects in your predicate. Also, the comparison operator >=/2 will evaluate expressions, so the separate is/2 is not required.

You can't use a variable for the name of a clause, you could write instead:
passed(Person,Subj):-
(Subj=history-> studies(Person, history(Work, Exam))
;Subj=chemistry-> studies(Person, chemistry(Work, Exam)),
Final is Work + Exam,
Final >=60.

Related

convert compound to atom in prolog

I want to use atom_chars/2 on the expression of 3+4, but I get
ERROR: atom_chars/2: Type error: 'atom' expected, found '3+4' (a compound).
I'm thinking that if I can add " " on both sides of the compound, it would work, e.g.
atom_chars("3+4", Result).
but I don't know how I can do that, or is there other approaches to do this?
Please give me some advice.
EDIT: What I mean is that the input has to be 3+4, instead of '3+4', so what I want to do is to write a predicate before the atom_chars/2 to convert 3+4 to '3+4'.
For instance: for compound2atom(X,Y),
-?compound2atom(3+4,Y).
Y='3+4'.
If you are using SWI-Prolog, there is with_output_to/2 or format/3:
?- with_output_to(atom(A), write(3+4)).
A = '3+4'.
?- with_output_to(chars(C), write(3+4)).
C = ['3', +, '4'].
?- format(atom(A), "~w", [3+4]).
A = '3+4'.
?- format(chars(C), "~w", [3+4]).
C = ['3', +, '4'].
But if you look hard enough you should be able to find some predicate that does that, for example term_to_atom/2.
My personal preference leans towards format/3.

Parse To Prolog Variables Using DCG

I want to parse a logical expression using DCG in Prolog.
The logical terms are represented as lists e.g. ['x','&&','y'] for x ∧ y the result should be the parse tree and(X,Y) (were X and Y are unassigned Prolog variables).
I implemented it and everything works as expected but I have one problem:
I can't figure out how to parse the variable 'x' and 'y' to get real Prolog variables X and Y for the later assignment of truth values.
I tried the following rule variations:
v(X) --> [X].:
This doesn't work of course, it only returns and('x','y').
But can I maybe uniformly replace the logical variables in this term with Prolog variables? I know of the predicate term_to_atom (which is proposed as a solution for a similar problem) but I don't think it can be used here to achieve the desired result.
v(Y) --> [X], {nonvar(Y)}.:
This does return an unbound variable but of course a new one every time even if the logical variable ('x','y',...) was already in the term so
['X','&&','X'] gets evaluated to and(X,Y) which is not the desired result, either.
Is there any elegant or idiomatic solution to this problem?
Many thanks in advance!
EDIT:
The background to this question is that I'm trying to implement the DPLL-algorithm in Prolog. I thought it would by clever to directly parse the logical term to a Prolog-term to make easy use of the Prolog backtracking facility:
Input: some logical term, e.g T = [x,'&&',y]
Term after parsing: [G_123,'&&',G_456] (now featuring "real" Prolog variables)
Assign a value from { boolean(t), boolean(f) } to the first unbound variable in T.
simplify the term.
... repeat or backtrack until a assignment v is found so that v(T) = t or the search space is depleted.
I'm pretty new to Prolog and honestly couldn't figure out a better approach. I'm very interested in better alternatives! (So I'm kinda half-shure that this is what I want ;-) and thank you very much for your support so far ...)
You want to associate ground terms like x (no need to write 'x') with uninstantiated variables. Certainly that does not constitute a pure relation. So it is not that clear to me that you actually want this.
And where do you get the list [x, &&, x] in the first place? You probably have some kind of tokenizer. If possible, try to associate variable names to variables prior to the actual parsing. If you insist to perform that association during parsing you will have to thread a pair of variables throughout your entire grammar. That is, instead of a clean grammar like
power(P) --> factor(F), power_r(F, P).
you will now have to write
power(P, D0,D) --> factor(F, D0,D1), power_r(F, P, D1,D).
% ^^^^ ^^^^^ ^^^^
since you are introducing context into an otherwise context free grammar.
When parsing Prolog text, the same problem occurs. The association between a variable name and a concrete variable is already established during tokenizing. The actual parser does not have to deal with it.
There are essentially two ways to perform this during tokenization:
1mo collect all occurrences Name=Variable in a list and unify them later:
v(N-V, [N-V|D],D) --> [N], {maybesometest(N)}.
unify_nvs(NVs) :-
keysort(NVs, NVs2),
uniq(NVs2).
uniq([]).
uniq([NV|NVs]) :-
head_eq(NVs, NV).
uniq(NVs).
head_eq([], _).
head_eq([N-V|_],N-V).
head_eq([N1-_|_],N2-_) :-
dif(N1,N2).
2do use some explicit dictionary to merge them early on.
Somewhat related is this question.
Not sure if you really want to do what you asked. You might do it by keeping a list of variable associations so that you would know when to reuse a variable and when to use a fresh one.
This is an example of a greedy descent parser which would parse expressions with && and ||:
parse(Exp, Bindings, NBindings)-->
parseLeaf(LExp, Bindings, MBindings),
parse_cont(Exp, LExp, MBindings, NBindings).
parse_cont(Exp, LExp, Bindings, NBindings)-->
parse_op(Op, LExp, RExp),
{!},
parseLeaf(RExp, Bindings, MBindings),
parse_cont(Exp, Op, MBindings, NBindings).
parse_cont(Exp, Exp, Bindings, Bindings)-->[].
parse_op(and(LExp, RExp), LExp, RExp)--> ['&&'].
parse_op(or(LExp, RExp), LExp, RExp)--> ['||'].
parseLeaf(Y, Bindings, NBindings)-->
[X],
{
(member(bind(X, Var), Bindings)-> Y-NBindings=Var-Bindings ; Y-NBindings=Var-[bind(X, Var)|Bindings])
}.
It parses the expression and returns also the variable bindings.
Sample outputs:
?- phrase(parse(Exp, [], Bindings), ['x', '&&', 'y']).
Exp = and(_G683, _G696),
Bindings = [bind(y, _G696), bind(x, _G683)].
?- phrase(parse(Exp, [], Bindings), ['x', '&&', 'x']).
Exp = and(_G683, _G683),
Bindings = [bind(x, _G683)].
?- phrase(parse(Exp, [], Bindings), ['x', '&&', 'y', '&&', 'x', '||', 'z']).
Exp = or(and(and(_G839, _G852), _G839), _G879),
Bindings = [bind(z, _G879), bind(y, _G852), bind(x, _G839)].

Prolog build rules from atoms

I'm currently trying to to interpret user-entered strings via Prolog. I'm using code I've found on the internet, which converts a string into a list of atoms.
"Men are stupid." => [men,are,stupid,'.'] % Example
From this I would like to create a rule, which then can be used in the Prolog command-line.
% everyone is a keyword for a rule. If the list doesn't contain 'everyone'
% it's a fact.
% [men,are,stupid]
% should become ...
stupid(men).
% [everyone,who,is,stupid,is,tall]
% should become ...
tall(X) :- stupid(X).
% [everyone,who,is,not,tall,is,green]
% should become ...
green(X) :- not(tall(X)).
% Therefore, this query should return true/yes:
?- green(women).
true.
I don't need anything super fancy for this as my input will always follow a couple of rules and therefore just needs to be analyzed according to these rules.
I've been thinking about this for probably an hour now, but didn't come to anything even considerable, so I can't provide you with what I've tried so far. Can anyone push me into the right direction?
Consider using a DCG. For example:
list_clause(List, Clause) :-
phrase(clause_(Clause), List).
clause_(Fact) --> [X,are,Y], { Fact =.. [Y,X] }.
clause_(Head :- Body) --> [everyone,who,is,B,is,A],
{ Head =.. [A,X], Body =.. [B,X] }.
Examples:
?- list_clause([men,are,stupid], Clause).
Clause = stupid(men).
?- list_clause([everyone,who,is,stupid,is,tall], Clause).
Clause = tall(_G2763):-stupid(_G2763).
I leave the remaining example as an easy exercise.
You can use assertz/1 to assert such clauses dynamically:
?- List = <your list>, list_clause(List, Clause), assertz(Clause).
First of all, you could already during the tokenization step make terms instead of lists, and even directly assert rules into the database. Let's take the "men are stupid" example.
You want to write down something like:
?- assert_rule_from_sentence("Men are stupid.").
and end up with a rule of the form stupid(men).
assert_rule_from_sentence(Sentence) :-
phrase(sentence_to_database, Sentence).
sentence_to_database -->
subject(Subject), " ",
"are", " ",
object(Object), " ",
{ Rule =.. [Object, Subject],
assertz(Rule)
}.
(let's assume you know how to write the DCGs for subject and object)
This is it! Of course, your sentence_to_database//0 will need to have more clauses, or use helper clauses and predicates, but this is at least a start.
As #mat says, it is cleaner to first tokenize and then deal with the tokenized sentence. But then, it would go something like this:
tokenize_sentence(be(Subject, Object)) -->
subject(Subject), space,
be, !,
object(Object), end.
(now you also need to probably define what a space and an end of sentence is...)
be -->
"is".
be -->
"are".
assert_tokenized(be(Subject, Object)) :-
Fact =.. [Object, Subject],
assertz(Fact).
The main reason for doing it this way is that you know during the tokenization what sort of sentence you have: subject - verb - object, or subject - modifier - object - modifier etc, and you can use this information to write your assert_tokenized/1 in a more explicit way.
Definite Clause Grammars are Prolog's go-to tool for translating from strings (such as your English sentences) to Prolog terms (such as the Prolog clauses you want to generate), or the other way around. Here are two introductions I'd recommend:
http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse29
http://www.pathwayslms.com/swipltuts/dcg/

Prolog syntax error: expression expected checking for parentheses

I'm writing a program in Prolog where I'm given a set of grammar rules and the user inputs a sentence, I must make sure the sentence follows the given rules.
I'm only stuck on one rule:
expr -> ( expr ) also written as expr -> ( id op expr )
Here is my code for this part:
expr(X) :- list(X), length(X, Length), =(Length, 5),
=(X, [Left, Id, Op, Expr | Right]),
=(Left, ‘(‘),
id(Id), op(Op), expr([Expr]),
=(Right, ‘)’).
I believe the issue is with checking the parentheses since the other parts of this code are used elsewhere with no errors. When using =(Left, '(') or =(Right, ')') I get a syntax error: expression expected why do I get this error and what would be a better way to check for left and right parentheses?
I think you should use single quotes here =(Left, ‘(‘), and here =(Right, ‘)’). I.e. =(Left, '('), and =(Right, ')').
That said, your Expr will only match a single token, and this is not what I expect. Consider to match the entire 'right' sequence with
X = [Left, Id, Op | Expr],
and further split Expr to get the right parenthesi. Anyway, as I advised in another answer, your parsing (also after correction) will fail on [a,=,'(',b,')',+,c].

Using "=" in Prolog

I'd like to know why I get an error with my SWI Prolog when I try to do this:
(signal(X) = signal(Y)) :- (terminal(X), terminal(Y), connected(X,Y)).
terminal(X) :- ((signal(X) = 1);(signal(X) = 0)).
I get the following error
Error: trabalho.pro:13: No permission to modify static procedure
'(=)/2'
It doesn't recognize the "=" in the first line, but the second one "compiles". I guess it only accepts the "=" after the :- ? Why?
Will I need to create a predicate like: "equal(x,y) :- (x = y)" for this?
Diedre - there are no 'functions' in Prolog. There are predicates. The usual pattern
goes
name(list of args to be unified) :- body of predicate .
Usually you'd want the thing on the left side of the :- operator to be a predicate
name. when you write
(signal(X) = signal(Y))
= is an operator, so you get
'='(signal(X), signal(Y))
But (we assume, it's not clear what you're doing here) that you don't really want to change equals.
Since '=' is already in the standard library, you can't redefine it (and wouldn't want to)
What you probably want is
equal_signal(X, Y) :- ... bunch of stuff... .
or
equal_signal(signal(X), signal(Y)) :- ... bunch of stuff ... .
This seems like a conceptual error problem. You need to have a conversation with somebody who understands it. I might humbly suggest you pop onto ##prolog on freenode.net or
some similar forum and get somebody to explain it.
Because = is a predefined predicate. What you actually write is (the grounding of terms using the Martelli-Montanari algorithm):
=(signal(X),signal(Y)) :- Foo.
You use predicates like functions in Prolog.
You can define something like:
terminal(X) :- signal(X,1);signal(X,0).
where signal/2 is a predicate that contains a key/value pair.
And:
equal_signal(X,Y) :- terminal(X),terminal(Y),connected(X,Y).

Resources