Is a predicate with variable arity acceptable in Prolog? - prolog

Is it possible to have a "variable arity predicate" in Prolog?
I mean something like this:
my_predicate( [a,b,c], [a,c], [a], [a,b,c,d], N, RESULT)
with the number of initial lists unknown at the beginning?
Using the univ operator ( =.. ) it would be possible to unify it with a list of terms and traversing it like every other list. But how to write the goal?
my_predicate(??) =.. [??]
I really don't know if this is even possible..

you can define predicates with different arities that have the same name but they will be different predicates.
foo(1).
foo(2,1).
?-foo(2).
false
my suggestion is to change the encoding; instead of a number of initial lists, have a list of initial lists.
the other solution would be to write predicates for all the possible numbers of arguments (or dynamically generate them).

As #thanosQR suggests, it probably is the best to change your representation to some list.
There are, however - very seldom but nevertheless - situations where you want to define a predicate for many different arities. In this very rare case, you can define such a predicate manually. That is, for each arity manually. Of course, you will only define several cases. As an example, see library(lambda).

You always can go up to one level :) Many years ago I saw implementation of ANSI prolog interpter in Turbo Prolog. Idea was very simple, enclose all user-space facts and rules in single fact backed by assert/retract-like operations.
Consider enclosing all your targets in another compose:
target(my_predicate( [a,b,c], [a,c], [a], [a,b,c,d], N, RESULT)) :- RESULT=[a], N=1.
target(H) :- H =.. [my_predicate|_].
target(using_my_predicate(X, Y)) :- target(my_predicate(X,1,Y)).
Some prologs (at least YAP) have directives to declare handlers for unknown targets:
:- module(sumtest).
target(sum(0)).
target(H) :-
H =.. [sum, S, X|XS],
H1 =.. [sum, S1|XS],
H1,
S is (S1+X).
target(sumtest:G):- target(G). % HACK: strip-off module
:- unknown(_, target(_)).
test:-
sum(X,1), write(X), nl,
sum(Y,2,3), write(Y), nl,
sum(Z,3,4,2), write(Z), nl,
target(sum(X1,1)), write(X1), nl,
target(sum(Y1,2,3)), write(Y1), nl,
target(sum(Z1,3,4,2)), write(Z1), nl.
:- test, halt.
% % yap -l sumtest.pl
% YAP 6.2.0 (amd64): Thu Oct 21 10:31:27 EEST 2010
% MYDDAS version MYDDAS-0.9.1
% 1
% 5
% 9
% 1
% 5
% 9
% % YAP execution halted

Related

negation \+ and vanilla meta-interpreter

The following is the classic "textbook" vanilla meta-interpreter for prolog.
% simplest meta-interpreter
solve(true) :- !.
solve((A,B)):- !, solve(A), solve(B).
solve(A) :- clause(A,B), solve(B).
The following is simple program which establishes facts two relations which are "positive" and one relation which makes use of negation by failure \+.
% fruit
fruit(apple).
fruit(orange).
fruit(banana).
% colour
yellow(banana).
% Mary likes all fruit
likes(mary, X) :- fruit(X).
% James likes all fruit, as long as it is yellow
likes(james, X) :- fruit(X), yellow(X).
% Sally likes all fruit, except yellow fruit
likes(sally, X) :- fruit(X), \+ (yellow(X)).
The meta-interpeter can handle goals related to the first two relations ?-solve(likes(mary,X)) and ?- solve(likes(james,X)_.
However it fails with a goal related to the third relation ?- solve(likes(sally,X). The swi-prolog reports a stack limit being reached before the program crashes.
Question 1: What is causing the meta-interpreter to fail? Can it be easily adjusted to cope with the \+ negation? Is this related to the sometimes discussed issue of built-ins not being executed by the vanilla meta-interpreter?
Question 2: Where can I read about the need for those cuts in the vanilla meta-interpreter?
Tracing suggests the goal is being grown endlessly:
clause(\+call(call(call(call(yellow(apple))))),_5488)
Exit:clause(\+call(call(call(call(yellow(apple))))),\+call(call(call(call(call(yellow(apple)))))))
Call:solve(\+call(call(call(call(call(yellow(apple)))))))
Call:clause(\+call(call(call(call(call(yellow(apple)))))),_5508)
Exit:clause(\+call(call(call(call(call(yellow(apple)))))),\+call(call(call(call(call(call(yellow(apple))))))))
Call:solve(\+call(call(call(call(call(call(yellow(apple))))))))
Change solve(A) into:
solve(Goal) :-
writeln(Goal),
sleep(1),
clause(Goal, Body),
solve(Body).
... and we see:
?- solve_mi(likes(sally,X)).
likes(sally,_8636)
fruit(_8636)
\+yellow(apple)
\+call(yellow(apple))
\+call(call(yellow(apple)))
\+call(call(call(yellow(apple))))
...
clause/2 determines the body of \+yellow(apple) to be \+call(yellow(apple)), which is not a simplification.
Can use instead:
solve_mi(true) :-
!.
solve_mi((Goal1, Goal2)):-
!,
solve_mi(Goal1),
solve_mi(Goal2).
solve_mi(\+ Goal) :-
!,
\+ solve_mi(Goal).
solve_mi(Goal) :-
clause(Goal, Body),
solve_mi(Body).
Result in swi-prolog:
?- solve_mi(likes(sally,X)).
X = apple ;
X = orange ;
false.
I'm using solve_mi because solve conflicts with e.g. clpBNR, and I'm not using variable names A and B because they convey no meaning.
For understanding the cuts, I'd recommend gtrace, to see the unwanted unification with other goals that would otherwise take place.

How do I print dynamic/1 in Prolog

I want to print these all names under each dynamic/1. For example I want to print all names of male under one query for print all males in Prolog.
The easiest way to do this in swi-prolog (and also in gnu-prolog) is to use predicate listing/1:
?- listing(male/1).
:- dynamic male/1.
male(saad).
male(sohaib).
male(salman).
...
true.
If you want more control over display formatting, you can define your own predicate as:
list_facts(Name/Arity) :-
functor(Head, Name, Arity),
forall( clause(Head, true),
format('~w.\n', [Head]) ). % Adjust formatting here!
Example:
?- list_facts(female/1).
female(rida).
female(florida).
female(yasmeen).
...
true.
If you want to show just the names, try:
?- forall(female(Name), format('~w\n', [Name])).
rida
florida
yasmeen
...
true.
REMARK The swi-prolog built-in predicate forall/2is defined as:
forall(Cond, Action) :-
\+ (Cond, \+ Action).
The supplied code works with SWI-Prolog, don't know if this works with other Prolog systems but the basis of the code should be portable.
This is from actual code I use daily so it more production quality code than simple answer code but the basis is to use functor/3 to get a head and then use the head in forall/2 to get the rules (rule/2) and format/3 to output each rule. Normally a rule is a head and body but since this is outputting facts only the heads are output. To convert the rules to individual values =../2 is used. This uses library(options). This also uses current_predicate/1 to check if the predicate exists to avoid an exception if it does not. functor/3 could probably be used but somewhere I recall a corner case that it did now work. The rest should not need explaining.
I only entered 3 of the male facts. Would have used all of them if they were typed as text into the question as then they could have been easily copied.
If the facts are in a different module remember to change the name of the module when calling list_facts/N.
:- module(examples,
[
list_facts/1,
list_facts/2,
list_facts/3
]).
:- dynamic female/1.
:- dynamic male/1.
male(saad).
male(sohaib).
male(salman).
list_facts(Module:Name/Arity) :-
list_facts(user_output,Module:Name/Arity,[]).
list_facts(Output_stream,Module:Name/Arity) :-
list_facts(Output_stream,Module:Name/Arity,[]).
list_facts(Output_stream,Module:Name/Arity,Options) :-
(
current_predicate(Module:Name/Arity)
->
(
option(left_margin_size(Left_margin_size),Options)
->
atomic_list_concat(['~|~',Left_margin_size,'+~|~w'],Format)
;
Format = '~w'
),
(
option(title(Title),Options)
->
format(Output_stream,Format,[Title]),
format(Output_stream,'~n',[])
;
true
),
functor(Head,Name,Arity),
forall(
rule(Module:Head,Rule),
list_fact(Output_stream,Format,Rule)
)
;
format(Output_stream,'No facts found: ~w:~w/~w.~n',[Module,Name,Arity])
).
list_fact(Output_stream,Format,Fact) :-
Fact =.. Fact_values,
list_values(Output_stream,Format,false,Fact_values).
% Recursive case - functor name
list_values(Output_stream,Format,false,[_Value|Values]) :-
!,
list_values(Output_stream,Format,true,Values).
% Recursive case - fact arguments
list_values(Output_stream,Format,true,[Value|Values]) :-
!,
format(Output_stream,Format,[Value]),
list_values(Output_stream,Format,true,Values).
% Base case
list_values(Output_stream,_Format,_Functor_done,[]) :-
format(Output_stream,'~n',[]).
Example usage.
?- working_directory(_,'C:/Users/Groot').
true.
?- [examples].
true.
?- list_facts(examples:male/1).
saad
sohaib
salman
true.
?- list_facts(user_output,examples:male/1,[left_margin_size(3),title('male/1')]).
male/1
saad
sohaib
salman
true.

I have defined multiple predicates that seem to share a common form

All of these predicates are defined in pretty much the same way. The base case is defined for the empty list. For non-empty lists we unify in the head of the clause when a certain predicate holds, but do not unify if that predicate does not hold. These predicates look too similar for me to think it is a coincidence. Is there a name for this, or a defined abstraction?
intersect([],_,[]).
intersect(_,[],[]).
intersect([X|Xs],Ys,[X|Acc]) :-
member(X,Ys),
intersect(Xs,Ys,Acc).
intersect([X|Xs],Ys,Acc) :-
\+ member(X,Ys),
intersect(Xs,Ys,Acc).
without_duplicates([],[]).
without_duplicates([X|Xs],[X|Acc]) :-
\+ member(X,Acc),
without_duplicates(Xs,Acc).
without_duplicates([X|Xs],Acc) :-
member(X,Acc),
without_duplicates(Xs,Acc).
difference([],_,[]).
difference([X|Xs],Ys,[X|Acc]) :-
\+ member(X,Ys),
difference(Xs,Ys,Acc).
difference([X|Xs],Ys,Acc) :-
member(X,Ys),
difference(Xs,Ys,Acc).
delete(_,[],[]).
delete(E,[X|Xs],[X|Ans]) :-
E \= X,
delete(E,Xs,Ans).
delete(E,[X|Xs],Ans) :-
E = X,
delete(E,Xs,Ans).
There is an abstraction for "keep elements in list for which condition holds".
The names are inclide, exclude. There is a library for those in SWI-Prolog that you can use or copy. Your predicates intersect/3, difference/3, and delete/3 would look like this:
:- use_module(library(apply)).
intersect(L1, L2, L) :-
include(member_in(L1), L2, L).
difference(L1, L2, L) :-
exclude(member_in(L2), L1, L).
member_in(List, Member) :-
memberchk(Member, List).
delete(E, L1, L) :-
exclude(=(E), L1, L).
But please take a look at the implementation of include/3 and exclude/3, here:
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/apply.pl?show=src#include/3
Also in SWI-Prolog, in another library, there are versions of those predicates called intersection/3, subtract/3, delete/3:
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#intersection/3
https://www.swi-prolog.org/pldoc/doc/_SWI_/library/lists.pl?show=src#subtract/3
https://www.swi-prolog.org/pldoc/doc_for?object=delete/3
Those are similar in spirit to your solutions.
Your next predicate, without_duplicates, cannot be re-written like that with include/3 or exclude/3. Your implementation doesn't work, either. Try even something easy, like:
?- without_duplicates([a,b], L).
What happens?
But yeah, it is not the same as the others. To implement it correctly, depending on whether you need the original order or not.
If you don't need to keep the initial order, you can simply sort; this removes duplicates. Like this:
?- sort(List_with_duplicates, No_duplicates).
If you want to keep the original order, you need to pass the accumulated list to the recursive call.
without_duplicates([], []).
without_duplicates([H|T], [H|Result]) :-
without_duplicates_1(T, [H], Result).
without_duplicates_1([], _, []).
without_duplicates_1([H|T], Seen0, Result) :-
( memberchk(H, Seen0)
-> Seen = Seen0 , Result = Result0
; Seen = [H|Seen0], Result = [H|Result0]
),
without_duplicates_1(T, Seen, Result0).
You could get rid of one argument if you use a DCG:
without_duplicates([], []).
without_duplicates([H|T], [H|No_duplicates]) :-
phrase(no_dups(T, [H]), No_duplicates).
no_dups([], _) --> [].
no_dups([H|T], Seen) -->
{ memberchk(H, Seen) },
!,
no_dups(T, Seen).
no_dups([H|T], Seen) -->
[H],
no_dups(T, [H|Seen]).
Well, these are the "while loops" of Prolog on the one hand, and the inductive definitions of mathematical logic on the other hand (See also: Logic Programming, Functional Programming, and Inductive Definitions, Lawrence C. Paulson, Andrew W. Smith, 2001), so it's not surprising to find them multiple times in a program - syntactically similar, with slight deviations.
In this case, you just have a binary decision - whether something is the case or not - and you "branch" (or rather, decide to not fail the body and press on with the selected clause) on that. The "guard" (the test which supplements the head unification), in this case member(X,Ys) or \+ member(X,Ys) is a binary decision (it also is exhaustive, i.e. covers the whole space of possible X)
intersect([X|Xs],Ys,[X|Acc]) :- % if the head could unify with the goal
member(X,Ys), % then additionally check that ("guard")
(...action...). % and then do something
intersect([X|Xs],Ys,Acc) :- % if the head could unify with the goal
\+ member(X,Ys), % then additionally check that ("guard")
(...action...). % and then do something
Other applications may need the equivalent of a multiple-decision switch statement here, and so N>2 clauses may have to be written instead of 2.
foo(X) :-
member(X,Set1),
(...action...).
foo(X) :-
member(X,Set2),
(...action...).
foo(X) :-
member(X,Set3),
(...action...).
% inefficient pseudocode for the case where Set1, Set2, Set3
% do not cover the whole range of X. Such a predicate may or
% may not be necessary; the default behaviour would be "failure"
% of foo/1 if this clause does not exist:
foo(X) :-
\+ (member(X,Set1);member(X,Set2);member(X,Set3)),
(...action...).
Note:
Use memberchk/2 (which fails or succeeds-once) instead of member/2 (which fails or succeeds-and-then-tries-to-succeed-again-for-the-rest-of-the-set) to make the program deterministic in its decision whether member(X,L).
Similarly, "cut" after the clause guard to tell Prolog that if a guard of one clause succeeds, there is no point in trying the other clauses because they will all turn out false: member(X,Ys),!,...
Finally, use term comparison == and \== instead of unification = or unification failure \= for delete/3.

Prolog - numbers to words

Im trying to write a code where if I run english(X). in Prolog I get a list of numbers 1-100 in linguistic form (one, two,....,twenty five,...,one hundred).
Is there a way to do this with a lexicon? I want to write a predicate for a pattern with how the "-teen" works. a predicate for the "-ty" and also a predicate for (twenty one, twenty two)? and when I say english(X). I should get a list of all the numbers. (one; two; three;....fifty one; .... one hundred. )
digit(0).
digit(1) :-
write(one).
digit(2) :-
write(two).
digit(3) :-
write(three).
digit(4) :-
write(four).
digit(5) :-
write(five).
digit(6) :-
write(six).
digit(7) :-
write(seven).
digit(8) :-
write(eight).
digit(9) :-
write(nine).
I have this so for and I am trying to write a predicate but having a hard time.
The links provided by Guy Coder give an excellent general case version.
Here is a solution that respects your starter code, although you should think about how you can make it neater and more general (including by consulting the links!)
english(X) :-
X<10, !,
digit(X).
english(X) :-
X<20, !,
teen(X).
english(X) :-
X<100, !,
Units is X mod 10,
Tens is X - Units,
tens(Tens),
digit(Units).
english(100) :-
write('one hundred').
teen(10) :-
write('ten'). % etc 10 to 19
tens(20) :-
write('twenty'). % etc 20 to 90
digit(0). % etc. 1 to 9 (as original digits)

Matching tuples in Prolog

Why does Prolog match (X, Xs) with a tuple containing more elements? An example:
test2((X, Xs)) :- write(X), nl, test2(Xs).
test2((X)) :- write(X), nl.
test :-
read(W),
test2(W).
?- test.
|: a, b(c), d(e(f)), g.
a
b(c)
d(e(f))
g
yes
Actually this is what I want to achieve but it seems suspicious. Is there any other way to treat a conjunction of terms as a list in Prolog?
Tuple term construction with the ,/2 operator is generally right-associative in PROLOG (typically referred to as a sequence), so your input of a, b(c), d(e(f)), g might well actually be the term (a, (b(c), (d(e(f)), g))). This is evidenced by the fact that your predicate test2/1 printed what is shown in your question, where on the first invocation of the first clause of test2/1, X matched a and Xs matched (b(c), (d(e(f)), g)), then on the second invocation X matched b(c) and Xs matched (d(e(f)), g), and so on.
If you really wanted to deal with a list of terms interpreted as a conjunction, you could have used the following:
test2([X|Xs]) :- write(X), nl, test2(Xs).
test2([]).
...on input [a, b(c), d(e(f)), g]. The list structure here is generally interpreted a little differently from tuples constructed with ,/2 (as, at least in SWI-PROLOG, such structures are syntactic sugar for dealing with terms constructed with ./2 in much the same way as you'd construct sequences or tuple terms with ,/2). This way, you get the benefits of the support of list terms, if you can allow list terms to be interpreted as conjunctions in your code. Another alternative is to declare and use your own (perhaps infix operator) for conjunction, such as &/2, which you could declare as:
:- op(500, yfx, &). % conjunction constructor
You could then construct your conjunct as a & b(c) & d(e(f)) & g and deal with it appropriately from there, knowing exactly what you mean by &/2 - conjunction.
See the manual page for op/3 in SWI-PROLOG for more details - if you're not using SWI, I presume there should be a similar predicate in whatever PROLOG implementation your'e using -- if it's worth it's salt :-)
EDIT: To convert a tuple term constructed using ,/2 to a list, you could use something like the following:
conjunct_to_list((A,B), L) :-
!,
conjunct_to_list(A, L0),
conjunct_to_list(B, L1),
append(L0, L1, L).
conjunct_to_list(A, [A]).
Hmm... a, b(c), d(e(f)), g means a and (b(c) and (d(e(f)) and g)), as well list [1,2,3] is just a [1 | [2 | [3 | []]]]. I.e. if you turn that conjuction to a list you'll get the same test2([X|Xs]):-..., but difference is that conjunction carries information about how that two goals is combined (there may be disjunction (X; Xs) as well). And you can construct other hierarchy of conjunctions by (a, b(c)), (d(e(f)), g)
You work with simple recursive types. In other languages lists is also recursive types but they often is pretending to be arrays (big-big tuples with nice indexing).
Probably you should use:
test2((X, Y)):- test2(X), nl, test2(Y).
test2((X; Y)). % TODO: handle disjunction
test2(X) :- write(X), nl.

Resources