How to evaluate a variable with string value? - prolog

My code does perfect with numbers, but error with single quotation. I'm trying to write a foldl function. When i do foldl1(concat, ['a','b'], X), it reports like "ERROR: Arithmetic: 'ab/0' is not a function". what is the problem? prolog does not allow using is with string?
foldl1(P, [H], X) :-
X is H.
foldl1(P, [H|T], X) :-
foldl1(P, T, Y),
call(P, H, Y, Z),
X is Z.

is/2 evaluates the arithmetic expression to the right, and unifies the result with the term to the left. Unification is also performed against the head' arguments, so you can write a simplified foldl1/3 like
foldl1(_, [H], H).
foldl1(P, [H|T], Z) :-
foldl1(P, T, Y),
call(P, H, Y, Z).
test:
?- foldl1(plus,[1,2,3],R).
R = 6 ;
false.
?- foldl1(concat,[1,2,3],R).
R = '123' ;
false.
I would place a cut after the recursion base, since [H] and [H|T] where T=[] overlap, to avoid any last call - that would anyway fail - on eventual backtracking, like the redo induced by me, inputting ; after the expected first answer while the interpreter waits for my choices.
After the cut (hope you can easily spot where to place it) we get:
?- foldl1(plus,[1,2,3],R).
R = 6.
?- foldl1(concat,[1,2,3],R).
R = '123'.
Now the interpreter 'knows' there are no more answers after the first...

It's also possible to implement a foldl1/3 predicate using first-argument indexing to avoid spurious choice-points without cuts and that is also tail-recursive. From the Logtalk library meta object:
:- meta_predicate(foldl1(3, *, *)).
foldl1(Closure, [Head| Tail], Result) :-
fold_left_(Tail, Closure, Head, Result).
fold_left_([], _, Result, Result).
fold_left_([Arg| Args], Closure, Acc, Result) :-
call(Closure, Acc, Arg, Acc2),
fold_left_(Args, Closure, Acc2, Result).
Sample calls:
?- meta::foldl1(plus,[1,2,3],R).
R = 6.
?- meta::foldl1(concat,[1,2,3],R).
R = '123'.

Related

Is there a non-unifying alternative to member/2 in SWI-Prolog?

In prolog, the difference between A = B and A == B is that = tries to unify A with B, while == will only succeed if A and B are already unified.
member/2 does seem to perform unification.
Example session:
?- A = B.
A = B.
?- A == B.
false.
?- member(A, [B]).
A = B.
I have been looking but I can't find a non-unifying alternative to member/2, but not found anything. Is there something built in or do I have to invent my own thing? As I'm rather new to Prolog I don't trust myself with writing a performant version of this.
EDIT:
I came up with the following, though I don't know if the cut is correct. Without it, it seems to deliver two answers for that branch of the code (true, followed by false) though. I'd also still like to know if there is a standard library function for this.
member_eq(_, []) :-
false.
member_eq(X, [H|_]) :-
X == H,
!.
member_eq(X, [_|T]) :-
member_eq(X, T).
You may slightly modify builtin predicate member/2 to use ==/2 instead of unification:
member_not_bind(X, [H|T]) :-
member_not_bind_(T, X, H).
member_not_bind_(_, X, Y):- X==Y.
member_not_bind_([H|T], X, _) :-
member_not_bind_(T, X, H).
Sample run:
?- L=[a,b,c(E)], member_not_bind(A, L).
false.
?- A=c(E),L=[a,b,c(E)], member_not_bind(A, L).
A = c(E),
L = [a, b, c(E)].
I leave this here as it solves a related question (checking if X may unify with any item in L without actually performing the bindings)
You can use double negation like this:
member_not_bind(X, L):- \+(\+(member(X, L))).
Sample runs:
?- A=c(e),L=[a,b,c(E)], member_not_bind(A, L).
A = c(e),
L = [a, b, c(E)].
?- A=d(E),L=[a,b,c(E)], member_not_bind(A, L).
false.

Can single sided unification improve error handling?

Inspired by this question, I am trying to harden error
handling of reverse/2. So I tried this implementation:
reverse(X, Y) :- reverse(X, [], Y).
reverse(X, _, _) :- var(X), throw(error(instantiation_error,_)).
reverse([], X, R) :- !, R = X.
reverse([X|Y], Z, R) :- !, reverse(Y, [X|Z], R).
reverse(X, _, _) :- throw(error(type_error(list,X),_)).
Everything works fine, until I try reverse/2 as a generator:
?- reverse([1,2,3],X).
X = [3, 2, 1].
?- reverse(2,X).
ERROR: Type error: `list' expected, found `2' (an integer)
?- reverse(X,Y).
ERROR: Arguments are not sufficiently instantiated
Can single sided unification change the situation, some typical solution based on single sided unification so that the generator reverse(X,Y) would still work? Single sided unification is available in SWI-Prolog 8.3.19.
I am afraid I cannot present a single sided unification solution. Its rather that normal unification in the form of (\=)/2 could be useful. I hardly use (\=)/2 ever. The solution is inspired by Dijkstra guards if-fi, link to paper at end of this post:
if
Cond1 -> ActionList1
..
Condn -> ActionList2
fi
The if-fi aborts if none of the conditions Cond1,..,Condn is satisfied. So we
simply use a conjunction of the negation of the conditions:
reverse(X, Y) :- reverse(X, [], Y).
reverse(X, _, _) :- X \= [], X \= [_|_], throw(error(type_error(list,X),_)).
reverse([], X, R) :- R = X.
reverse([X|Y], Z, R) :- reverse(Y, [X|Z], R).
Seems to work:
?- reverse([1,2,3],X).
X = [3, 2, 1].
?- reverse(2,X).
ERROR: Type error: `list' expected, found `2' (an integer)
?- reverse(X,Y).
X = Y, Y = [] ;
X = Y, Y = [_1778] ;
X = [_1778, _2648],
Y = [_2648, _1778] ;
Etc..
So single sided unification might be the wrong approach? I dont know. The above solution incures an overhead, unless some indexing might optimize away (\=)/2. Could even work in connection with attributed variables.
Nondeterminacy and Formal Derivation of Programs
Edsger W. Dijkstra - Burroughs Corporation
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.90.97&rep=rep1&type=pdf
This seems to work (a straightforward translation to use => of reverse/2 in library(lists)):
reverse(List, Reversed) =>
reverse(List, [], Reversed, Reversed).
reverse([], Ys, Reversed, Tail) =>
Reversed = Ys,
Tail = [].
reverse([X|Xs], Rs, Reversed, Tail) =>
Tail = [_|Bound],
reverse(Xs, [X|Rs], Reversed, Bound).

The unification algorithm in Prolog

I'm trying to program the unification algorithm in Prolog to verify if two expressions can unify by returning boolean True/False:
EDIT.
I found this implementation usefull:
from: http://kti.mff.cuni.cz/~bartak/prolog/data_struct.html
unify(A,B):-
atomic(A),atomic(B),A=B.
unify(A,B):-
var(A),A=B. % without occurs check
unify(A,B):-
nonvar(A),var(B),A=B. % without occurs check
unify(A,B):-
compound(A),compound(B),
A=..[F|ArgsA],B=..[F|ArgsB],
unify_args(ArgsA,ArgsB).
unify_args([A|TA],[B|TB]):-
unify(A,B),
unify_args(TA,TB).
unify_args([],[]).```
Here is a partial implementation of something like the Martelli and Montanari unification algorithm described at https://en.wikipedia.org/wiki/Unification_(computer_science)#A_unification_algorithm. The comments for each part refer to the corresponding rewrite rule from the algorithm. Note that there is no need for an explicit conflict rule, we can just fail if no other rule applies.
% assuming a universe with function symbols g/2, p/2, q/2
% identical terms unify (delete rule)
unify(X, Y) :-
X == Y,
!.
% a variable unifies with anything (eliminate rule)
unify(X, Y) :-
var(X),
!,
X = Y.
% an equation Term = Variable can be solved as Variable = Term (swap rule)
unify(X, Y) :-
var(Y),
!,
unify(Y, X).
% given equal function symbols, unify the arguments (decompose rule)
unify(g(A, B), g(X, Y)) :-
unify(A, X),
unify(B, Y).
unify(p(A, B), p(X, Y)) :-
unify(A, X),
unify(B, Y).
unify(q(A, B), q(X, Y)) :-
unify(A, X),
unify(B, Y).
Examples:
?- unify(q(Y,g(a,b)), p(g(X,X),Y)).
false.
?- unify(q(Y,g(a,b)), q(g(X,X),Y)).
false.
?- unify(q(Y,g(a,a)), q(g(X,X),Y)).
Y = g(a, a),
X = a.
One or two things remain for you to do:
Generalize the decompose rule to deal with arbitrary terms. You might find the =.. operator useful. For example:
?- Term = r(a, b, c), Term =.. FunctorAndArgs, [Functor | Args] = FunctorAndArgs.
Term = r(a, b, c),
FunctorAndArgs = [r, a, b, c],
Functor = r,
Args = [a, b, c].
You will need to check if two terms have the same functor and the same number of arguments, and whether all corresponding pairs of arguments unify.
Find out if your professor would like you to implement the occurs check, and if yes, implement it.

Prolog's built-in reverse function acting odd

Given the following code:
fun(a, [b]).
fun(b, [c]).
fun(c, [d]).
fun(d, [e]).
fun(e, []).
xyz(X, Y):-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
flatten(L,F), sort(F,J), reverse(J,Y); Y = [].
With the query xyz(a,X) I get the expected output X = [e,d,c,b]..
What could possibly be throwing this off? Does this have to do with the sort function? If so, according to the documents in the links below, alpha or numeric order of precedence could be throwing this off, but it still doesn't explain by cs40 is going before cs30. I am having a hard time finding a correlation. How can I fix this issue?
http://www.swi-prolog.org/pldoc/doc_for?object=sort/2
http://www.swi-prolog.org/pldoc/man?section=compare
By the way, the fun function could have multi-element lists such as fun(a, [b,c], where a has multiple dependencies b and c. This aspect shouldn't matter too much regarding the current issue that I have, but just getting this fact out there.
UPDATE
Thanks to #lurker, I've made some great progress.
Given the following code:
final_xyz(X, Y):- xyz(X, R), reverse(R, Y).
xyz(X, Y) :-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
flatten(L,Y); Y = [].
In an attempt to fix this, I updated the code to:
xyz-final(X,Y):-
fun(X,Z),
Z\=0,
( length(Z,1) -> xyz(X,J), reverse(J,Y)
;
xyz2(X,B), sort(B,C), reverse(C,Y)
).
xyz(K, [X|Y]):- fun(K, [X]), !, xyz(X, Y).
xyz(_, []).
xyz2(X, Y) :-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz2(A,B)), L),
flatten(L,Y); Y = [].
Very clumsy approach, but this seems to work for me now. I'll work on making it more efficient.
The issue is that you are wanting to reverse the final result, but your reverse is being done in each recursive call to xyz/2. If you do a trace on your xyz(cs140a, X) call, you'll see it's being called a few times on different recursions.
If you want it once at the end, then you can write it this way:
final_xyz(X, Y) :-
xyz(X, R),
reverse(R, Y).
xyz(X, Y) :-
fun(X,Z) -> findall([A|B], (member(A,Z), xyz(A,B)), L),
flatten(L,Y); Y = [].
And then calling final_xyz(cs140a, X) yields, X = [m16a,cs30,cs40,cs110].
Here's an alternative approach to your xyz predicate which avoids the findall and the flatten. This version should avoid cyclical paths and doesn't show duplicates:
xyz(X, Y) :-
fun(X, L),
xyz(L, [], R),
reverse(R, Y).
xyz([H|T], A, R) :-
( memberchk(H, A)
-> xyz(T, A, R)
; fun(H, L)
-> xyz(L, [H|A], R1),
xyz(T, R1, R)
; xyz(T, [H|A], R)
).
xyz([], A, A).

Regarding two implementations of min_of_list in prolog

Can someone explain clearly why this implementation (from SO 3965054) of min_of_list works in prolog:
% via: http://stackoverflow.com/questions/3965054/prolog-find-minimum-in-a-list
min_of_list_1( [H], H).
min_of_list_1([H,K|T],M) :- H =< K, min_of_list_1([H|T],M).
min_of_list_1([H,K|T],M) :- H > K, min_of_list_1([K|T],M).
while this implementation generates an incorrect output:
min_of_list_2( [H], H).
min_of_list_2( [H| T], X) :- compare(<, X, H), min_of_list_2(T, X).
min_of_list_2( [H| T], H) :- compare(>, X, H), min_of_list_2(T, X).
min_of_list_2( [H| T], H) :- compare(=, X, H), min_of_list_2(T, H).
Epilogue. This works.
min_of_list_3( [H], H).
min_of_list_3( [H| T], X) :- min_of_list_3(T, X), compare(<, X, H).
min_of_list_3( [H| T], H) :- min_of_list_3(T, X), compare(>, X, H).
min_of_list_3( [H| T], H) :- min_of_list_3(T, X), compare(=, X, H).
?
The behavior I get is that min_of_list_2 returns the last element in the list.
Thanks.
The first clause of min_of_list_2/2 is OK, it says the minimum of a list with a single element is that element. The second clause is not quite so OK: The intention seems to state that if X is the minimum of the list T, and X is smaller than H, then X is also the minimum of the list [H|T], and this would work as intended if compare/3 behaved like a true relation, but unfortunately it doesn't:
?- compare(<, a, b).
true.
Yet the more general query fails as if there were no solution (although we know there is at least one!):
?- compare(<, a, X).
false.
Since one typical usage of min_of_list_2/2 (including for example its use in the third clause) leaves the second argument uninstantiated, you will run into this problem. Your code will work as expected if you place all calls of compare/3 after the respective recursive calls of min_of_list_2/2. As a consequence, your predicate is then no longer tail recursive, in contrast to the other program you posted. The compare/3 call in the last clause should be removed (what is the X in that case?), as it will always fail!
the first one compares the first two elements of the list and then puts the min again in the list till there is only one element.
the second one... takes the head of the list and compares with X. X is non-instantiated in the first call so compare(<,X,_any_number) will be true. X wont be instantiated so the same will repeat till there is only one element in the list which will be returned* (the last one).
'* where returned = unified with the second argument.

Resources