Related
I tried this vanilla interpreter:
solve(true) :- !, true.
solve(X is E) :- !, X is E.
solve((A,B)) :- !, solve(A), solve(B).
solve(H) :- clause(H,B), solve(B).
Can we use it to meta-interpret some code? I tried this code,
requires SWI-Prolog 8.3.19, which runs fine normally:
sumlist([X|Y], R) => sumlist(Y, H), R is X+H.
sumlist([], R) => R is 0.
?- sumlist([1,2,3],X).
X = 6.
?- sumlist(X,Y).
ERROR: No rule matches sumlist(_21604,_21606)
But meta-interpretation goes wrong. The reason is that clause/2
doesn’t know about rules that use single sided unification:
?- clause(sumlist(A,B),C).
A = [_22728|_22730],
C = (sumlist(_22730, _22736), B is _22728+_22736) ;
A = [],
C = (B is 0).
?- solve(sumlist([1,2,3],X)).
X = 6.
?- solve(sumlist(X,Y)).
SWI-Prolog wurde unerwartet beendet.
Is there a solution for meta-interpreters and single sided unification?
One way out of the dilemma and stay inside the ISO core standard, is to translate single sided unfication to a combination of nonvar/1, (=)/2 and (==)/2, like here:
?- clause(sumlist(X,Y),Z), write((sumlist(X,Y):-Z)), nl, fail; true.
sumlist(_A, _B) :- nonvar(_A), _A = [_C|_D], sumlist(_D, _E), _B is _C+_E
sumlist(_A, _B) :- nonvar(_A), _A = [], _B is 0
Of course we need to add the built-ins nonvar/1, (=)/2 and (==)/2 as well to the meta interpreter:
solve(true) :- !.
solve(X is E) :- !, X is E.
solve(nonvar(X)) :- !, nonvar(X).
solve(X == Y) :- !, X == Y.
solve(X = Y) :- !, X = Y.
solve((A, B)) :- !, solve(A), solve(B).
solve(H) :- clause(H, B), solve(B).
Meta-interpreting sumlist/2 now works fine:
?- solve(sumlist([1,2,3],X)).
X = 6
?- solve(sumlist(X,Y)).
No
But the translator might challenge a Prolog system concering clause indexing. It moves away the functors from the head into the body. So the Prolog system would need some body front indexing as pioneered by YAP and found in Jekejeke Prolog.
Open Source:
Yet Another Pattern Matcher
https://gist.github.com/jburse/a3517410a28b759ef44f72584f89aaf8#file-picat3-pl
Vanilla Interpreter, Expansion Solution
https://gist.github.com/jburse/a3517410a28b759ef44f72584f89aaf8#file-vanilla4-pl
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)
I wonder whether there is a pure Prolog meta-interpreter with
only one rule. The usual Prolog vanilla meta-interpreter has two
rules. It reads as follows:
solve(true).
solve((A, B)) :- solve(A), solve(B). /* rule 1 */
solve(H) :- program(H, B), solve(B). /* rule 2 */
This Prolog vanilla meta-interpreter uses two rules /* rule 1 */
and /* rule 2 */. And the rest is facts. The program that
is executed is represented by program facts. Here is an example program:
program(append([], X, X), true).
program(append([X|Y], Z, [X|T]), append(Y, Z, T)).
program(nrev([], []), true).
program(nrev([H|T], R), (nrev(T, S), append(S, [H], R))).
And an example query:
?- solve(nrev([1,2,3], X)).
X = [3, 2, 1] .
Is there a way to represent the program differently as facts, and
then code a different meta-interpreter, which would use only facts
except for a single rule instead of two rules? Something that would
work for all pure Prolog programs, not only the nrev example?
Here is one idea, using a list to hold the rest of the computation:
solve([]).
solve([X|Xs]) :- program(X, Ys, Xs), solve(Ys).
program(true, Xs, Xs).
program(append([],X,X), Xs, Xs).
program(append([X|Y], Z, [X|T]), [append(Y,Z,T)|Xs], Xs).
program(nrev([],[]), Xs, Xs).
program(nrev([H|T],R), [nrev(T,S),append(S,[H],R)|Xs], Xs).
With test call (where one needs to wrap the call in a list).
?- solve([nrev([1,2,3],X)]).
X = [3,2,1] ? ;
no
Arguably, one could represent the program/3 facts as a DCG instead, for increased readability (but then it might not be considered a "fact" any more).
Here is another approach, known as binarization with continuation.
Its from this logic transformers paper here by Paul Tarau (2021).
solve(true).
solve(X) :- program(X, Y), solve(Y).
program(append([],X,X,C), C).
program(append([X|Y],Z,[X|T],C), append(Y,Z,T,C)).
program(nrev([],[],C), C).
program(nrev([H|T],R,C), nrev(T,S,append(S,[H],R,C))).
A little sanity check shows that it wurks:
?- solve(nrev([1,2,3], X, true)).
X = [3, 2, 1] ;
No
If ;/2 is allowed, then this seems to work:
solve(true).
solve(H) :- ((X, Y) = H, solve(X), solve(Y)); (program(H :- B), solve(B)).
program(append([], X, X) :- true).
program(append([X|Y], Z, [X|T]) :- append(Y, Z, T)).
program(nrev([], []) :- true).
program(nrev([H|T], R) :- (nrev(T, S), append(S, [H], R))).
Test:
?- solve(nrev([1,2,3], X)).
X = [3, 2, 1] ;
false.
I have the next matrix:
map(1,[[1,0,0,0,0,0,0,0,0,0],
[1,1,0,0,1,1,0,0,0,0],
[0,1,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,1,0,0,0,1,0,0,0],
[0,1,1,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,1,1,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0]]).
I want to print this matrix like this:
-if the matrix element value is 0 -> print('~')
-if the matrix element value is 1 -> print('#').
I tried to do this, but my method print false everytime. This is my code:
print_encoded([H|T]) :-
H==0 ->
write('~');
H==1 ->
write('#');
print_encoded(T).
showEncoded :-
map(_,Map),
print_encoded(Map).
Maybe this is a easy question, but prolog is a new programming language for me. Thanks in advance for your help.
You have no base case for [] for print_encoded.
It could be
print_encoded([]) :-
nl.
You can use a "functional spirit" with module lambda of SWI-Prolog
:- use_module(library(lambda)).
print_encoded(M) :-
maplist(\X^(maplist(\Y^(Y = 0
-> write('~')
; write('#')),
X),
nl),
M).
maplist seems has been built on purpose of such tasks...
encode_map(M) :- maplist(maplist(encode_cell), M).
encode_cell(0) :- write('~').
encode_cell(1) :- write('#').
I have a set of facts:
likes(john,mary).
likes(mary,robert).
likes(robert,kate).
likes(alan,george).
likes(alan,mary).
likes(george,mary).
likes(harry,mary).
likes(john,alan).
Now I want to write a relation which will check for all element X of an input list if likes(X,A) is true. my relation should return true once if likes(X,A) is true for all element X in my list L.
If I try this this:
relat(X) :- member(A,[john,alan,george,harry]), likes(A,X).
but the output is
?- relat(mary).
true ;
true ;
true ;
true.
I want to write it such that it returns one true once it found that likes(john,mary),likes(alan,mary),likes(george,mary),likes(harry,mary) all are true.
How to approach this problem?
In SWI-Prolog, you can use forall/2:
?- forall(member(A, [john, alan, george, harry]), likes(A, mary)).
true.
?- forall(member(A, [john,alan,george,harry,marys_ex]), likes(A, mary)).
false.
With standard list processing you can do the following:
helper(X, []). % No one left to check
helper(X, [H|L]) :- likes(H, X), helper(X, L). % Check head, then rest
relat(X) :- helper(X, [john,alan,george,harry]).
Demo:
| ?- relat(harry).
no
| ?- relat(mary).
true ? ;
no
| ?-
Using library(lambda):
liked_byall(X, Ps) :-
maplist(X+\P^likes(P,X), Ps).
Equally without lambdas:
liked_byall(X, Ps) :-
maplist(liked(X), Ps).
liked(X, P) :-
likes(P, X).
Equally:
liked_byall(_X, []).
liked_byall(X, [P|Ps]) :-
likes(P, X),
liked_byall(X, Ps).
With above definitions you can ask even more general questions like "Who is liked by certain persons?"
?- liked_byall(N,[john, alan, george, harry]).
N = mary
; false.
With the following definition these general questions are no longer possible.
liked_byall(X, Ps) :-
\+ ( member(P, Ps), \+ likes(P, X) ).
This second definition only makes sense if X is ground and Ps is a ground list. We can ensure this as follows:
liked_byall(X, Ps) :-
( ground(X+Ps) -> true ; throw(error(instantiation_error,_)) ),
length(Ps,_),
\+ ( member(P, Ps), \+ likes(P, X) ).
These extra checks ensure that absurd cases as the following do not succeed:
?- liked_byall(mary, nonlist).
And that otherwise legitimate cases do not produce an incorrect answer:
?- liked_byall(N,[john, alan, george, harry]), N = the_grinch.
N = the_grinch.