Related
According to my university's course in logic we could expect a different outcome than defined by Prolog for the following query:
append([], a, X)
(which unifies for X=a).
However I don't get what they're aiming at? What should be expected as a valid response, given that append should unify X for (in this example) the concatenation of [] and a?
I assume they may be expecting a return of false or [a]; however I suppose that should be the result of concatenating a and [], not [] and a (since [] is the tail of [a]).
The point here is that we expect append/3 to hold only for lists.
In the query you show, a is not a list, yet append/3 still holds.
Thus, the relation is in fact more general than we would initially expect: It holds for other cases too!
The reason why this is so can be soon from the first clause of the traditional definition of append/3:
append([], Bs, Bs).
This clause alone already makes the query succeed! No additional pure clause can prevent this. Thus, it is this clause that must be restricted if we want the relation to hold only for lists. This means, we must put a constraint on the second argument, which we do by stating it in the body of the clause:
append([], Bs, Bs) :- ... (left as an exercise)
This obviously comes at a price: Performance.
So, the trade-off here is between performance and precision. In Prolog, we often accept such a trade-off because we implicitly use such predicates only with the intended terms. On the other hand, for many predicates, we want to benefit from domain errors or type errors if they are not called with the expected types.
Your course is aiming at a very important point of Prolog programming.
Manuals are often quite sloppy on the precise definition of append/3 and similar predicates. In fact, the complete definition is so complex that it is often preferred to define only part of the actual relation. Consider the first definition in the Prolog prologue:
append(Xs, Ys, Zs) is true if Zs is the concatenation of the lists Xs and Ys.
Note the if. The definition thus gives cases, where the relation holds but does not explicitly exclude further cases. To exclude further cases, it would say iff instead. The cases mentioned (that we are talking about lists) are the intended use of the predicate. So which cases now may be additionally included? Those cases where the precondition (that the arguments are lists) does not hold.
Consider a definition of append/3 with 'iff' in place of 'if':
append([], Xs, Xs) :-
list(Xs).
append([X|Xs], Ys, [X|Zs]) :-
append(Xs, Ys, Zs).
list([]).
list([X|Xs]) :-
list(Xs).
The cost for appending two lists is now |Xs|+|Ys|. That is quite an overhead compared to |Xs| alone.
But the situation is even worse. Consider the query:
?- append([1,2], Ys, Zs).
; Ys = [], Zs = [1,2]
; Ys = [_A], Zs = [1,2,_A]
; Ys = [_A,_B], Zs = [1,2,_A,_B]
; ... .
So we get infinitely many answers to this query. Contrast this to the usual definition:
?- append([1,2], Ys, Zs).
Zs = [1,2|Ys].
There is a single answer only! It contains all the answers for all lists plus some odd cases as you have observed. So the usual definition for append has better termination properties. In fact, it terminates if either the first or the third argument is a list of known length1.
Note that the answer contains Ys. In this manner infinitely many answers can be collapsed into a single one. This in fact is the power of the logical variable! We can represent with finite means infinitely many solutions. The price to pay are some extra solutions2 that may lead to programming errors. Some precaution is thus required.
1 It also terminates in some further obscure cases like append([a|_],_,[b|_]).
2 append([a], Zs, Zs). produces (in many systems) an answer, too.
However I don't get what they're aiming at?
Knowing exactly what they are aiming at is of course impossible without asking them.
Nevertheless I think they aim to show that Prolog is (more or less) untyped. append/3 is documented as:
append(?List1, ?List2, ?List1AndList2)
List1AndList2 is the concatenation of List1 and List2.
So clearly one expects that the three arguments are lists and a is not a list. a is not the concatenation of [] and a since one would consider the two not "concatenatable".
Now this still succeeds, because append/3 is usually implemented as:
append([],T,T).
append([H|T],T2,[H|R]) :-
append(T,T2,R).
So if you give it append([],a,X)., it will simply unify with the first clause and unify X = a.
The same "weird" behavior happens with append([14],a,X). Here X = [14|a] which is not a list as well. This is because the Prolog interpreter does not "know" it is working with lists. For Prolog [A|B] is the same like any other functor.
A more "type safe" way to handle this could be:
append([],[],[]).
append([H|T],T2,[H|R]) :-
append(T,T2,R).
append([],[H|T],[H|R]) :-
append([],T,R).
Or more elegantly:
list([]).
list([_|T]) :-
list(T).
append([],T,T) :-
list(T).
append([H|T],T2,[H|R]) :-
append(T,T2,R).
since here we check whether the second argument is a list. The downside however is that now we will append/3 in O(m+n) with m the length of the first list and n the length of the second list whereas in the original code it would take only O(m) time. Furthermore note that Prolog will not raise a warning/error at parse time. It will only fail to append [] with a at the moment you query these.
Not checking types results in the fact that you have less guarantees if the program compiles/does not raises errors when you feed it to an interpreter. This can be a good thing, but a problem might be that you call some predicates in a way they don't expect which may raise errors eventually later. That is why statically typed languages are sometimes used: they "guarantee" (at least to some extent) that if you call the problem, no such errors will occur. Of course that does not mean that the program cannot error on other things (or simply make no sense). haskell for instance is statically typed and has an append like:
(++) [] t2 = t2
(++) (h:t) t2 = h:((++) t t2)
The definition is "more or less" the same, but Haskell will derive that the type of (++) is (++) :: [a] -> [a] -> [a]. Because it know the type of the input and output of every function, it can perform calculus on it, and therefore at compile time, it will raise errors if you would give (++) something different than a list.
Whether that is a good thing is of course a different question: dynamically typed programming languages are designed that way deliberately since it allows more flexibility.
I'm trying to further my understanding of Prolog, and how it handles unification. In this case, how it handles unification with lists.
This is my knowledgebase;
member(X, [X|_]).
member(X, [_|T]):- member(X, T).
If I'm understanding the process correctly. If member(X, [X|_]) is not true, then it moves into the recursive rule, and if X is in list T, then [_|T] is unified with T.
So what happens to the anonymous variable in my recursive predicate? Does it get discarded? I'm having difficulty understanding the exact unification process with lists, as [_|T] is two variables, rather than one. I'm just trying to figure out how the unification process works precisely with lists.
Assume that _ is Y
member(X, [Y|T]):- member(X, T).
Then this is True regardless Y. Now you are "returning" member(X, T). In other words, you are discarding Y and "returning" member(X, T).
_ means, whatever it is, ignore that variable.
The _ is just like any other variable, except that each one you see is
treated as a different variable and Prolog won't show you what it
unifies with. There's no special behavior there; if it confuses you
about the behavior, just invent a completely new variable and put it
in there to see what it does.
In your case, your function check if a given element exists on a list, so, you take first element of the list, check if is equal, if not, you discard that element and moves on.
I think your primary question of how lists are represented as variables has been adequately answered, but I sense there are some other aspects to Prolog that need clarification.
To understand Prolog predicates and clauses, it's a good idea not to think of them as "functions" that "return" things, even metaphorically. It can lead you down the dark path of imperative thinking in Prolog. :)
In considering the predicate:
(1) member(X, [X|_]).
(2) member(X, [_|T]) :- member(X, T).
Think of member/2 as a relation which describes when element X is a member of the list L, and the clauses are the rules for determining when it is true.
I'll assume that you already know about how lists are represented in Prolog based upon other answers (e.g., Will Ness' detailed answer).
The first clause says:
(1) X is a member of [X|_] regardless of what the tail of the list [X|_] is
In that notation, the variable _ represents the tail of list [X|_] and X represents the first element of that list. It's trivially true that X is a member of this list, so member(X, [X|_]). is a fact. It's true regardless of what the tail of the list is, so we just use _ (an anonymous variable) since this rule doesn't need the information. Prolog doesn't technically "throw the value away" but the programmer throws it away because the programmer isn't using it. If we had, instead, said, member(X, [X|T]). that would work fine, but we're not using T. Prolog might instantiate it, but it wouldn't be used. It's like assigning x = 3 in C but not using it's value. In this case, Prolog will indicate a warning about a "singleton" variable. Watch for those, because it often means you misspelled something or forgot something. :)
The next rule is recursive. It says:
(2) X is a member of list [_|T] if X is a member of the tail (T) of that list, regardless of what the first element of the list is
Here we're considering the less trivial case where the first element in the list may not be a match to X, so the truth value of member(X, L) depends, in this rule, upon the truth value of member(X, T) where T is the tail (everything but the first element) of L. The rule does not unify member(X, [_|T]) with member(X, T), so it does not unify T with [_|T] as you might suppose. The :- operator defines a rule or implication (note the if in the rule description). [N.B., If you were to unify these terms, it would be done with with the unification operator, =/2: member(X, [_|T]) = member(X, T)].
On the recursive query member(X, T), Prolog goes back to the top, the first rule, and attempts to unify the first argument X with the head of the second argument (which is the original list minus its first element, or head) and, if it doesn't match, goes to rule #2 again, continually checking the tail as well, until it can unify. If it gets to the point where the tail is empty ([]) and hasn't been able to unify X with any elements, the predicate fails because there are no facts or rules that match member(X, []). However, if it does unify X with an element, it succeeds (it does not "return a value* in the sense that a function would in other languages) and reveals the values of any variables it instantiated in the arguments in the process, or simply will succeed if all the arguments passed are already instantiated. If there are more rules to check after succeeding (there was what's called a choice point), it will (if you tell it to) go back and check for more solutions and, if it finds them, display them as well. Or display no or false if there are no more.
Looking at an example query, is b a member of [a,b,c]?
member(b, [a,b,c]).
Prolog will first try to unify the query with a fact or the head of a predicate. The first one it finds is:
member(X, [X|_]).
In attempting to unify, X = b, but [a,b,c] (or, [a|[b,c]] in the head-tail notation) doesn't unify with [b|_](note the head elementsaandb` mismatch). Prolog then moves on to the next clause:
member(X, [_|T]) :- member(X, T).
In unifying member(b, [a,b,c]) with the head, it comes up with:
member(b, [_|[b,c]]) :- member(b, [b,c]).
It now has the recursive query to chase down: member(b, [b,c]). Since it's a new query, it starts at the top again and attempts to unify this with member(X, [X|_]). Now, it's successful, because member(b, [b,c]) (or, member(b, [b|[c]])) matches this pattern: member(b, [b|_]).
Therefore, the member(b, [a,b,c]). succeeds and Prolog will return "true". However, it's not done yet because it left what's called a choice point. Even though it matched member(b, [b,c]) with the first clause, it will still want to go back and find more cases that make it succeed, and there's still another clause to pursue. So, Prolog will go back and try member(b, [b,c]) against the second clause, matching member(b, [b|[c]]) to member(b, [_|[c]]) and doing another recursive query, member(b, [c]) and so on until it ultimately fails to find another solution. This is why the query looks something like this:
| ?- member(b, [a,b,c]).
true ? ;
no
| ?-
It first succeeds, but then we ask for more (with ;) and it then fails (no). This confuses some Prolog beginners, but it's because we've asked Prolog to get another solution, and it said there are none.
Because Prolog continues to try to find solutions (upon request), you can also use a variable in the query:
member(E, [a,b,c]).
This query runs the same way as the prior example, but now I have a variable as the first argument. Prolog will successfully match this to the first clause: member(E, [a,b,c]) unifies with member(X, [X|_]) via E = a. So you'll see something like:
| ?- member(E, [a,b,c]).
E = a ?
If we now ask for more solutions with ;, Prolog goes back and attempts the second clause, unifying member(E, [a|[b,c]]) with member(X, [_|T]) yielding _ = a (which is ignored in the predicate) and T = [b,c]. It then recursively queries, member(E, [b,c]) and, since it's a new query, goes back to the top and matches member(X, [X|_]) again, this time with E = b. So we see:
| ?- member(E, [a,b,c]).
E = a ? ;
E = b ?
And so on. member(E, [a,b,c]) will find all the values of E which make member(E, [a,b,c]) true and then finally fail after exhausting all the elements of [a,b,c]).
[A|B] represents a list where A is the Head element and B is the whole rest list.
So to explain you the algorithm shortly:
Clause: If X is the first element of the list the predicate succeeds.
Clause: If that's not the case, we try to find X in the tail of the list. Therefore, we call member recursively but instead of passing the whole list we now pass the list EXCEPT the head element. In other words, we walk through the list step by step always looking at the head element first. If that is not our element, we dig further.
Think of the anonymous variable _ just as a variable you do not need later. The algorithm would also work, if you replaced _ by a capital letter, however it would give you a warning that you named a variable that you never use.
A list is just a compound term with the '.' functor:
1 ?- [_|T] = .(_,T).
true.
2 ?- [_|T] =.. X.
X = ['.', _G2393, T].
The usual process of structural unification of compound terms apply:
3 ?- [A|T] = .(B,R).
A = B,
T = R.
[A|T] is really .(A,T) so the functors (.) and the arities (both terms are binary, of arity 2) match, so the respective constituents are matched as well.
Yes, the anonymous variable _ is ignored for the purposes of reporting the unification results. Otherwise it is just a fresh uniquely named variable.
it moves into the recursive rule, and if X is in list T, then [_|T] is unified with T.
Not quite. The unification happens before the "moving on", as part of the clause selection. To unify a list L with [_|T] is to select its "tail" and have T referring to it. E.g.
4 ?- L = [1,2,3], L = [_|T].
L = [1, 2, 3],
T = [2, 3].
(_ is 1 but is not reported).
When you call member(Item, List) with an uninstanciated list, Prolog unifies and returns a list containing item. I want a rule that returns true/false and does not try to unify. Is there such a rule?
Quick answer: Use \+ \+ member(Item, List).
Please note that such tests often do not make a lot of sense when your programs represent logical relations.
You stated that member(Item, List) "returns a list". Well, that is not entirely true. List is unified with partial lists, that is List = [Item|_Rest] ; List = [_,Item|_Rest] ; ... with _Rest being an uninstantiated variable. That is, the goal member(Item, List) does not guarantee that (upon success) List is a list. Here is a counterexample: member(Item, List), List = [_|nonlist]
I would use a guard, like
is_member(E, L) :- nonvar(L), memberchk(E, L).
memberchk/2 it's a deterministic version of member/2, to be used to find if the list contains at least 1 occurrence of element. Cannot act as a generator, but it's more efficient. The guard is required anyway.
Is there any difference between input and output parameters in Prolog predicate definitions? How does this this compare with other languages such as Scheme and C?
I hope I understand your question. You should look into how unification is implemented in Prolog, as it will make things clearer. Anyway:
Briefly, there is no built-in way to declare an argument to a Prolog predicate as input, output, or input/output.
In C, you could say:
void foo(int const *a, int *b)
{
*b += *a;
}
and you could argue that in the context of foo, a is an input argument, while b is an output argument. In Prolog, you can use this notation when describing predicates, but there is no way to declare in the head of the predicate definition that an argument must be bound or a free variable when the predicate is called. And anyway, most predicates in pure Prolog have arguments that can be input, output, or input/output, depending how the predicate is used. Look at the list library of SWI-Prolog for many examples.
You can of course demand that an argument is instantiated, or a free variable, but this is done in the body of the predicate definition:
add_2(A, B) :- integer(A), var(B), B is A+2.
Compare this to:
plus_2(A, B) :- integer(A), integer(B), B =:= A+2.
which checks whether B=A+2 holds true, instead of adding 2 to A and unifying the result with B. integer/1, var/1, and the other predicates that verify the type of a term cannot be implemented in pure Prolog.
In my very limited experience with Prolog, I have noticed that one will try to define predicates that work as long as enough arguments are instantiated to either:
Instantiate the other variables according to the logic of the predicate
Infer whether the relationship between the arguments described by the predicate holds true.
For example, length(List, Integer) can tell you how long a list is, make a list of uninstantiated variables of the given length, or check whether the list is that long.
What you can do, however, is have a ground term in the head of the predicate definition, for example foo(1). This sort of predicates are called facts. A clause with a ground term in the head is the usual way for defining the end-of-recursion for recursive predicates.
Is there any difference between the input/output parameters in Prolog definitions?
No, and in fact a parameter can be either one depending on how it is used. Boris's length example is a good one, because you can calculate length:
?- length([1,2,3], X).
X = 3.
Or test an answer:
?- length([1,2,3], 3).
true.
Or generate a list of specified length:
?- length(X, 3).
X = [_G273, _G276, _G279].
Or even generate lists and lengths:
?- length(X, Y).
X = [],
Y = 0 ;
X = [_G15],
Y = 1 ;
X = [_G15, _G18],
Y = 2 ;
...
So you see either argument of length/2 can be instantiated or not and you'll still get meaningful answers. Not every predicate in Prolog is this flexible, but many are.
How does this this compare with other languages such as scheme and C ?
This is the principal difference between Prolog and other languages. There is no other, better-known language which behaves analogously to help you grok it. It means that, among other differences, there is no implicit "return value," you must have a parameter to pass results back in, but you're not limited to just one result parameter. In the case where both arguments to length/2 were uninstantiated, they were both acting as return values.
By convention, you will want to write your predicates so that input parameters go before output parameters for the common cases (or at least, in a sensible way for the name you've chosen).
I am new to prolog and was trying to create a binary predicate which will give
a list in which all numbers are squared, including those in sublists.
e.g.
?-dcountSublists([a,[[3]],b,4,c(5),4],C).
C=[a,[[9]],b,c(5),16]
Can anyone guide me how i can do this.
Thank You. Answer with a snippet is appreciated
This is easily achieved using recursion in Prolog. Remember that everything in Prolog is either a variable, or a term (atoms are just 0-arity terms), so a term like the following:
[a,[[3]],b,4,c(5),4]
...is easily deconstructed (also note that the list syntax [..] is sugar for the binary predicate ./2). Prolog offers a range of predicates to test for particular types of terms as well, such as numbers, strings, or compound terms (such as compound/1).
To build the predicate you're after, I recommend writing it using several predicates like this:
dcountSublists(In, Out) :-
% analyze type of In
% based on type, either:
% 1. split term into subterms for recursive processing
% 2. term cannot be split; either replace it, or pass it through
Here's an example to get you started which does the hard bit. The following recognizes compound terms and breaks them apart with the term de/constructor =../2:
dcountSublists(In, Out) :-
% test if In has type compound term
compound(In),
% cut to exclude backtracking to other cases below this predicate
!,
% deconstruct In into functor and an argument list
In =.. [Func|Args],
% apply dcountSublists/2 to every argument, building new args
maplist(dcountSublists, Args, NewArgs),
% re-construct In using the new arguments
Out =.. [Func|NewArgs].
dcountSublists(In, Out) :-
% test if In has type atom
atom(In), !,
% pass it through
Out = In.
Testing:
?- dcountSublists([a,[[e]],b,a,c(s),a], L).
L = [a, [[e]], b, a, c(s), a].
Note that this fails if the input term has numbers, because it doesn't have a predicate to recognize and deal with them. I'll leave this up to you.
Good luck!
SWI-Prolog has the predicate maplist/[2-5] which allows you to map a predicate over some lists.
Using that, you only have to make a predicate that will square a number or the numbers in a list and leave everything else the same. The predicates number/1, is_list/1 are true if their argument is a number or a list.
Therefore:
square(N,NN):-
integer(N),
NN is N*N.
square(L,LL):-
is_list(L),
dcountSublists(square,L,LL).
square(Other,Other):-
\+ number(Other),
\+ is_list(Other).
dcountSublists(L,LSquared):-
maplist(square,L,LSquared).
with the negation in the final predicate we avoid multiple (wrong) solutions:
for example dcountSublists([2],X) would return X=[4] and X=[2] otherwise.
This could be avoided if we used an if-then-else structure for square or once/1 to call square/2.
If this is homework maybe you should not use maplist since (probably) the aim of the exercise is to learn how to build a recursive function; in any case, I would suggest to try and write an equivalent predicate without maplist.