Use "univ" Prolog predicate with a Logtalk object method as parameter - prolog

How to use the 'Univ' ( =../2 ) prolog predicate with a Logtalk object method as parameter ?
Consider this code :
baz(foo(X)) :-
write(predicate), write(X), nl.
run :-
Term =.. [baz, foo(testfoo)],
write(Term), nl, Term,nl,
TermLgt =.. [bar::baz, foo(testfoo2)],
write(TermLgt), nl, Term,nl.
:- object(bar).
:- public(baz/1).
baz(foo(X)) :-
write(method), write(X), nl.
:- end_object.
:- object(main).
:- public(run/0).
run :-
Term =.. [baz, foo(testfoo)],
write(Term), nl, Term,nl,
TermLgt =.. [bar::baz, foo(testfoo2)],
write(TermLgt), nl, Term,nl.
:- end_object.
I'll obtain :
?- {myfile}.
% (0 warnings)
true.
?- run.
baz(foo(testfoo))
predicatetestfoo
ERROR: =../2: Type error: `atom' expected, found `bar::baz' (a compound)
?- main::run.
baz(foo(testfoo))
ERROR: Undefined procedure: baz/1
ERROR: However, there are definitions for:
ERROR: baz/1
What workaround to use for a good interpretation / compilation ? It seems issue is the same with swi-prolog building predicate like predsort/3 (predsort/3 doc).

The standard =../2 predicate expects, when constructing a term from a list, that the first list argument be an atom but bar::baz is a compound term with functor ::/2 (which is both defined as a predicate - for top-level queries - and as an operator when Logtalk is loaded). The solution is to write instead:
baz(foo(X)) :-
write(predicate), write(X), nl.
run :-
Term =.. [baz, foo(testfoo)],
write(Term), nl, call(Term), nl,
TermLgt =.. [::, bar, Term],
write(TermLgt), nl, call(Term), nl.
:- object(bar).
:- public(baz/1).
baz(foo(X)) :-
write(method), write(X), nl.
:- end_object.
:- object(main).
:- public(run/0).
run :-
Term =.. [baz, foo(testfoo)],
write(Term), nl, Term,nl,
TermLgt =.. [::, bar, Term],
write(TermLgt), nl, Term,nl.
:- end_object.
With this changes, you get:
?- {univ}.
% [ /Users/pmoura/Desktop/univ.lgt loaded ]
% (0 warnings)
true.
?- run.
baz(foo(testfoo))
predicatetestfoo
bar::baz(foo(testfoo))
predicatetestfoo
true.

Related

Why does SWI-Prolog fail when mentioning a predicate without any facts in a rule?

Here is my Prolog program:
:- set_prolog_flag(verbose, silent).
:- initialization(main).
:- use_module(library(tabling)).
:- table reachable/1.
reachable(X) :- start(X).
reachable(X) :- reachable(Y), link(Y, X).
start(london).
% link(london, paris).
% link(paris, london).
% link(london, frankfurt).
% link(paris, frankfurt).
% link(frankfurt, paris).
main :-
forall(reachable(X), writeln(X)),
halt.
main :-
halt(1).
Running it gives this error:
swipl links.pl
Initialization goal raised exception:
ERROR: 'reachable tabled'/1: Undefined procedure: link/2
However this works:
:- set_prolog_flag(verbose, silent).
:- initialization(main).
:- use_module(library(tabling)).
:- table reachable/1.
reachable(X) :- start(X).
reachable(X) :- reachable(Y), link(Y, X).
start(london).
link(tokyo, hongkong).
main :-
forall(reachable(X), writeln(X)),
halt.
main :-
halt(1).
swipl links.pl
london
How can I make my program work with and without and link facts?
swipl --version
SWI-Prolog version 7.6.4 for amd64
If you intend to dynamically add the facts to the database later (for example via assertz/2 or asserta/2) you should use the directive dynamic/1:
:-dynamic link/2.
This prevents bugs in your program due to typos.

How to link constant with variable by assert?

I want to add in the DB a constant and a linked variable:
?- assertz(my(x, A))
So that in the future I can define A and get the only one entry. Sth like that:
?- assertz(my(x, A)), ..., A = 2.
?- my(A, B).
A = x,
B = 2.
Can this be done?
As I noted in the comments your idea of a link like a pointer is not the way to approach solving your problem.
A common solution is to walk the tree and construct a new tree as you walk the tree by replacing the leaf of the tree with a new leaf that contains the value from the input tree along with the associated value, what you are thinking should be linked.
Since you are somewhat new to Prolog I will do this with two examples. The first will just walk a tree and only return true when successfully walked. It can be used to understand how to walk a tree and run with gtrace to single step the code to understand it.
The second example will expand on the tree walk and add the type (link as you think) to the leaf item. The the old leaf for something simple like an atom a, will become a new leaf in the tree like (a,atom).
Also this was quickly written as a demonstration only. I am sure it will have problems if pressed into doing anything more than the single example.
:- module(example,
[
example/1
]).
example(walk) :-
Term = term_size(a(1,"Hello",'Atom',1+2,[a,$,T])),
walk(Term).
example(infer_type) :-
Term = term_size(a(1,"Hello",'Atom',1+2,[a,$,T])),
infer_type(Term,Is),
write(Is).
walk([]) :- !.
walk([T]) :- var(T), !.
walk(L) :- is_list(L), !, L = [H|T], walk(H), walk(T).
walk(T) :- compound(T), !, T =.. [_|Args], !, walk(Args).
walk(T) :- integer(T), !.
walk(T) :- var(T), !.
walk(T) :- atomic(T), !.
walk(T) :- T =.. [Arg|Args], !, walk(Arg), walk(Args).
infer_type([],[]) :- !.
infer_type([T],[(T,var)]) :- var(T), !.
infer_type(L,S) :- is_list(L), !, L = [H|T], infer_type(H,I), infer_type(T,Is), S = [I|Is].
infer_type(T,S) :- compound(T), !, T =.. [F|Args], !, infer_type(Args,Is), S =.. [F|Is].
infer_type(T,(T,integer)) :- integer(T), !.
infer_type(T,(T,var)) :- var(T), !.
infer_type(T,(T,atom)) :- atomic(T), !.
infer_type(T,S) :- T =.. [Arg|Args], !, infer_type(Arg,I), infer_type(Args,Is), S =.. [I|Is].
Example run
Note: I know there are warnings; it is a demo not production code.
Welcome to SWI-Prolog (threaded, 64 bits, version 8.5.3)
?- working_directory(_,'C:/Users/Groot').
true.
?- [example].
Warning: c:/users/Groot/example.pl:20:
Warning: Singleton variables: [T]
Warning: c:/users/Groot/example.pl:24:
Warning: Singleton variables: [T]
true.
?- example(walk).
true.
?- example(infer_type).
term_size(a((1,integer),(Hello,atom),(Atom,atom),(1,integer)+(2,integer),[(a,atom),(($),atom),(_25642,var)]))
true.
As an exercise I did not identify the string as a string, the change should be easy.

Simulating occurs_check=error in SICStus Prolog

It turns out that SICStus Prolog doesn't have an occurs_check
Prolog flag. At least we couldn't find one, and this here
gives an error message:
/* SICStus 4.6.0 (x86_64-win32-nt-4) */
?- set_prolog_flag(occurs_check, true).
Domain error in argument 1 of set_prolog_flag/2
It seems the value "true" is not so much a problem, the
crictical unifications can be realized via the existing
built-in unify_with_occurs_check/2. An interesting value
of an occurs_check Prolog flag is the value "error".
How would one implement a predicate unify_with_occurs_check_and_error/2 ?
Please note, the solution for unify_with_occurs_check_and_error/2
should behave like unify_with_occurs_check/2, i.e. not trigger
attributed variables.
Here is an example usage of the Prolog flag where present:
?- set_prolog_flag(occurs_check, error).
true.
?- X = f(X).
ERROR: ...
And this is what one would do in SICStus Prolog:
?- unify_with_occurs_check_and_error(X, f(X)).
ERROR: ...
Was adapting the code from here and got the following solution:
unify_with_error(X, Y) :- var(X), var(Y), !, X = Y.
unify_with_error(X, Y) :- var(X), !, must_notin(X, Y), X = Y.
unify_with_error(X, Y) :- var(Y), !, must_notin(Y, X), X = Y.
unify_with_error(X, Y) :- functor(X, F, A), functor(Y, G, B),
F/A = G/B,
X =.. [_|L],
Y =.. [_|R],
maplist(unify_with_error, L, R).
must_notin(X, Y) :-
term_variables(Y, L),
maplist(\==(X), L), !.
must_notin(X, Y) :-
throw(error(occurs_check(X, Y),_)).
Seems to work and no interference with attributed variables:
/* SICStus 4.6.0 (x86_64-win32-nt-4) */
?- unify_with_error(X, f(X)).
error(occurs_check(_413,f(_413)),_409)
?- freeze(X, throw(ball)), unify_with_error(X, f(X)).
error(occurs_check(_413,f(_413)),_409)

Prolog combinatoric of two lists ignoring the last items

I'm trying to get the combinatorics of two lists ignoring the last element of both.
the code:
isady(_, [_]) :-
write('stop here'),
nl,
false.
isady(E, [H|T]) :-
write(E),
write('-'),
write(H),
nl,
isady(E, T).
ady([_], _) :-
write('stop here'),
nl,
false.
ady([H|T], L2) :-
isady(H, L2);
ady(T, L2).
output:
?- ady([a,b,c], [d,e,f]).
a-d
a-e
stop here
a-f
b-d
b-e
stop here
b-f
stop here
c-d
c-e
stop here
c-f
expected output:
?- ady([a,b,c], [d,e,f]).
a-d
a-e
b-d
b-e
As you can see, it doesn't stop when it has to, does anyone knows why?
Try this:
isady(_, [_]) :-
write('stop here'),
nl,
false.
isady(E, [H|T]) :-
T\=[],
write(E),
write('-'),
write(H),
nl,
isady(E, T).
ady([_], _) :-
write('stop here'),
nl,
false.
ady([H|T], L2) :-
T\=[],
isady(H, L2);
ady(T, L2).
The new condition T \= [] will prevent the use of the last elements of both lists.
[EDIT] You can also explicitly use the pattern for a list of length at least 2, to avoid the execution of the "step case" clause with lists of length 1:
isady(_, [_]).
isady(E, [X,Y|T]) :-
writeln(E-X),
isady(E,[Y|T]).
ady([_], _).
ady([X,Y|T], L) :-
isady(X, L),
ady([Y|T], L).
Result:
?- ady([a,b,c], [d,e,f]).
a-d
a-e
b-d
b-e
true ;
false.

Use assertz while within a clause within swi-prolog

I'm trying to make a modified version of the expert system example within swi-prolog.org. I'm trying to modify it to be able to do:
good_pet(X) :- bird(X), small(X).
good_pet(X) :- cuddly(X), small(X).
good_pet(X) :- cuddly(X), yellow(X).
Without the program reasking if small() or cuddly is true.
I tried doing:
:- dynamic ([small/1, cuddly/1 ]).
good_pet(X) :- bird(X), assertz(small(X)).
good_pet(X) :- bird(X), small(X).
good_pet(X) :- assertz(cuddly(X)), assertz(small(X)).
good_pet(X) :- cuddly(X), small(X).
good_pet(X) :- cuddly(X), yellow(X).
As expained here.
But that ends up giving this error:
No permission to access private_procedure `assertz/1'
In:
[4] clause(assertz(cuddly(tweety)),_1306)
[3] prove(assertz(cuddly(tweety))) at line 11
[2] prove((assertz(...),assertz(...))) at line 8
[1] prove(good_pet(tweety)) at line 12
Is there a solution to this error or any another way to save the result of the asked questions?
The meta-interpreter that you are trying to use does not take into account clauses that call built-in predicates such as assertz/1. Try:
prove(true) :- !.
prove((B, Bs)) :- !,
prove(B),
prove(Bs).
prove(H) :-
predicate_property(H, built_in),
!,
call(H).
prove(H) :-
clause(H, B),
prove(B).
prove(H) :-
askable(H),
writeln(H),
read(Answer),
Answer == yes.

Resources