Related
I'm trying to learn prologue, but man am I having trouble.
I have an example below as well as what it outputs, and I'm clearly stuck on some concepts but not sure what.
output([]).
output([c|R]):- output(R), !, nl.
output([X|R]) :- output(R), write(X).
?- output([a,b,c,d,e]).
Answer:
ed
ba
true.
Correct me if I'm wrong, but here is what I understand so far...
When we call output([a,b,c,d,e]).
prologue looks for a solution using unification,
it tries output([]) and fails, so it proceeds to the second output([c|R]) which then passes the tail of the list recursively into output([c|R]) until it hits the base case of output([]).
Now I get confused...It then hits the cut which locks R to [] and c with a value of e? how does the output afterwards happens? I'm really confused.
I think you're having a fundamental misunderstanding of what Prolog is doing and what unification is about. In Prolog when you make a query such as output([a,b,c,d,e]). Prolog will start from the beginning of your asserted facts and predicates and attempt to unify this term (your query) with a fact or the head of a predicate.
Unification
We need to stop here for a moment and understand what unification is. In Prolog, the operator =/2 is the unification operator and can be used to query the unification of two terms, term1 = term2. This query will succeed if term and term2 can be successfully unified. How can they be successfully unified? This can happen if there is a binding of variables in term1 and term2 such that the terms become, essentially, identical (by "essentially" I mean they might differ only in syntactic representation but are truly identical when in canonical form - see details below on what that is).
Here are examples of unification attempts that fail. You can enter these at a Prolog prompt and it will show immediate failure.
a = e. % This fails because the atom `a` is different than the atom `e1`
% There are no variables here that can change this fact
foo(X) = bar(Y)
% This fails because the functor `foo` is different than
% the functor `bar`. There's no way to get these terms to match
% regardless of how the variables `X` or `Y` might be instantiated
foo(a, Y) = foo(b, Y)
% This fails because no matter how the variable `Y` is instantiated
% the 1st argument of `foo` just cannot match. That is, the atom
% `a` doesn't match the atom `b`.
foo(a, b, X) = foo(a, b)
% This fails because the `foo/3` and `foo/2` have a different
% number of arguments. No instantiation of the variable `X` can
% change that fact
[1,2] = [1,2,3] % Fails because a list of 2 elements cannot match a list of 3 elements
[] = [_|_] % Fails because the empty list cannot match a list of at
% least one element.
[a,b,c] = [x|T] % Fails, regardless of how `T` might be bound, because `[a,b,c]`
% is a list whose first element is `a`
% and `[x|T]` is a list whose first element is `x`. The
% atoms `a` and `x` do not and cannot match.
Here are examples of successful unifications. You can test these as well at a Prolog prompt and you should get success or, if variables are involved, get at least one solution showing binding of variables that causes it to succeed:
a = a. % Trivial case: an atom successfully unifies with itself
X = a. % Succeeds with `X` bound to `a`
foo(X) = foo(a). % Succeeds with `X` bound to `a`
[a,b,c] = [a|T] % Succeeds with `T` bound to `[b,c]` because the first element
% `a` is the same in both cases.
[1,2,3] = [H|T] % Succeeds with `H` bound to 1, and `T` bound to `[2,3]`
% since `[1,2,3]` is equivalent to `[1|[2,3]]` (they are two
% different syntaxes representing the same term)
Just an aside: Prolog list syntax
We're writing lists using a form that's familiar from other languages. So [] is an empty list, and [1,2,3] is a list of the 3 elements 1, 2, and 3. You can also have lists inside of lists, or any terms in a list for that matter. This, for example, is a valid list of 3 elements: [a, [1,foo(a)], bar(x,Y,[])]. The first element is a, the second is a list of two elements, [1, foo(a)], and the third element is bar(x,Y,[]). In Prolog, you can also write a list in a form that describes the first of one or more elements and a tail. For example [H|T] is a list whose first element is H and the rest of the list is T (itself a list). A list of at least two elements could be written as [H|T] and you'd know that T has at least one element. Or you could write it as [H1,H2|T] and explicitly indicate the first two elements and understand that T would be a list of zero or more arguments. The first elements are individual elements of the list, and the tail is a list representing the rest of the list. The following forms all represent the list [a,b,c,d,e]:
[a,b,c,d,e]
[a|[b,c,d,e]]
[a,b|[c,d,e]]
[a,b,c|[d,e]]
[a,b,c,d|[e]]
[a,b,c,d,e|[]]
If you had a list, L, and wanted prolog to ensure that L had at least two arguments, you could unify L with an anonymous list of 2 elements: L = [_,_|_]. This will only succeed if L is a list of at least two elements.
Another aside: canonical form
Prolog, though, has what it calls a canonical form for terms which is its fundamental representation of a given term. You can see the canonical form of a term by calling write_canonical(Term):
| ?- write_canonical([a,b,c]).
'.'(a,'.'(b,'.'(c,[])))
yes
So that's interesting, what on earth is that? It doesn't look like a list at all! It's actually the canonical form in Prolog of what a list really looks like to Prolog (if you want to think of it that way). The fundamental term form in Prolog is a functor and zero or more arguments. The atom a is a term which could be viewed as a functor a with no arguments. The term foo(1,X) has functor foo and arguments 1 and X. The list [a,b,c] written that way is just a convenient syntax for programmers that make it easy to read. A list is actually formed by the functor '.' and two arguments: the head and the tail. So the list [H|T] in general is '.'(H,T) and the empty list [] is just itself, an atom representing the empty list. When Prolog unifies (or attempts to unify) two lists, it's really looking at a list as '.'(H, T) so it matches the '.' functor, then attempts to match arguments. In the case of multiple elements, it's a recursive match since T is itself a list.
Expressions in Prolog such as X + 3 are also a syntactic convenience for the canonical form, '+'(X, 3).
Back to our story
As we were saying, when you query output([a,b,c,d,e])., Prolog tries to unify this with heads of predicate clauses or facts that you have already asserted. Here's what you have asserted:
output([]).
output([c|R]):- output(R), !, nl.
output([X|R]) :- output(R), write(X).
Starting from the top, Prolog attempts this unification:
output([a,b,c,d,e]) = output([])
This fails since there are no variables to change the terms to make them match. It fails because the list [a,b,c,d,e] and the empty list [] cannot match.
On to the next clause:
output([a,b,c,d,e]) = output([c|R])
This can only succeed if the unification [a,b,c,d,e] = [c|R] can succeed with some binding of R. You can look at this as [a|[b,c,d,e,]] = [c|R]. Clearly, for this unification to succeed, the first element of each list must match. But a and c don't match, so this fails.
On to the next one:
output([a,b,c,d,e]) = output([X|R])
Prolog attempts then to unify [a,b,c,d,e] with [X|R], or [a|[b,c,d,e]] with [X|R]... and this succeeds since X and R are variables and they can be bound as X = a and R = [b,c,d,e]. Now the body of the clause can be executed:
output([b,c,d,e]), write(a).
Before we can get to the write(a), the call output([b,c,d,e]) must execute first and succeed. Following the same logic above, the the first and second clauses of the output/1 predicate do not match. But the 3rd clause matches again with [b,c,d,e] = [X|R] resulting in X = b and R = [c,d,e]. Now the body of this clause is executed again (and you must remember we're now one level deep in a recursive call... the above call to output([b,c,d,e]) is pending awaiting the result):
output([c,d,e]), write(b).
Now it gets more interesting. The first clause of output/1 still doesn't match since [c,d,e] = [] fails. But the second clause now does match since [c,d,e] = [c|R] succeeds with the binding R = [d,e]. So that body is executed:
output([d,e]), !, nl.
Now we need to chase down the call to output([d,e]) (we're now another level deep in recursion remember!). This one fails to match the first two clauses but matches the 3rd clause, by [d,e] = [X|R] with bindings X = d and R = [e].
I could keep going but I'm getting tired of typing and I do have a real job I work at and am running out of time. You should get the idea hear and start working through this logic yourself. The big hint moving forward is that when you finally get to output([]) in a recursive call an you match the first clause, you will start "unwinding" the recursive calls (which you need to keep track of if you're doing this by hand) and the write(X) calls will start to be executed as well as the !, nl portion of the second clause in the case where c was matched as the first element.
Have fun...
The main problem with your reasoning is that c is not a variable but an atom. It cannot be unified with any other value.
So with your example input, for the first 2 calls it will not execute output([c|R]) (since a nor b can be unified with c), but it goes on to output([X|R]) instead. Only for the third call, when the head is c, the former clause is called. After this it will call the latter clause another 2 times for d and e, and then it hits the base case.
From that point on we can easily see the output: if first writes 'e', then 'd', then a new line (for the time we matched c), ad then b and a. Finally you get true as output, indicating that the predicate call succeeded.
Also note that due to the cut we only get a single output. If the cut wasn't there, we would also get edcba, since the c case would also be able to match the last clause.
I'm trying to find the available slot which comes from the predicate quizslots/3 quizslot(Group, Day, Slot).
quizslot(group4, tuesday, 1).
quizslot(group4, thursday, 1).
quizslot(group6, saturday, 5).
This is my hypothesis but it doesn't seem to work fine.
available_timings(G,L):-
setof(X,quizslot(G,X,_),L).
I want the result for (group4,L), L = [tuesday,1,thursday,1].
Syntax of setof:
% Set of every FooResult
?- setof(FooResult,foo(X,Y,FooResult),Result).
[FooResult1, FooResult2, ..]
% Set of tuples of every input X and FooResult
?- setof((X,FooResult),foo(X,Y,FooResult),Result).
[(X1,FooResult1), (X2,FooResult2), ..]
% Set of lists of every input X and FooResult, ommitting input Y
?- setof([X,FooResult],foo(X,_,FooResult),Result).
[[X1,FooResult1], [X2,FooResult2], ..]
I think you get the point. As lurker stated in his answer above, you are trying to have the slot included in the result, however, you tell prolog to find all distinct quizslot-facts of the form:
quizslot(group G, day X, whatever slot)
Since this wildcard will match with any slot, you cannot retrieve the actual variable holding the slot, Prolog didn't bother retrieving the variable for you.
A correct usage would be, for example, one of the following
setof([Day,Slot], quizslot(Group,Day,Slot), Result) % List of lists
setof((Day,Slot), quizslot(Group,Day,Slot), Result) % List of tuples
I am working through sample questions while studying, using SWI-Prolog. I have reached the last section of this question, where I have to recursively (I hope) compare elements of a list containing 'researcher' structures to determine whether or not the researchers have the same surname, and, if they do, return the Forename and Surname of the group leader for that list.
There is only one list that meets this criteria and it has four members, all with the same surname. However, the correct answer is returned FOUR times. I feel my solution is inelegant and is lacking. Here is the question:
The following Prolog database represents subject teaching teams.
% A research group structure takes the form
% group(Crew, Leader, Assistant_leader).
%
% Crew is a list of researcher structures,
% but excludes the researcher structures for Leader
% and Assistant_leader.
%
% researcher structures take the form
% researcher(Surname, First_name, expertise(Level, Area)).
group([researcher(giles,will,expertise(3,engineering)),
researcher(ford,bertha,expertise(2,computing))],
researcher(mcelvey,bob,expertise(5,biology)),
researcher(pike,michelle,expertise(4,physics))).
group([researcher(davis,owen,expertise(4,mathematics)),
researcher(raleigh,sophie,expertise(4,physics))],
researcher(beattie,katy,expertise(5,engineering)),
researcher(deane,fergus,expertise(4,chemistry))).
group([researcher(hardy,dan,expertise(4,biology))],
researcher(mellon,paul,expertise(4,computing)),
researcher(halls,antonia,expertise(3,physics))).
group([researcher(doone,pat,expertise(2,computing)),
researcher(doone,burt,expertise(5,computing)),
researcher(doone,celia,expertise(4,computing)),
researcher(doone,norma,expertise(2,computing))],
researcher(maine,jack,expertise(3,biology)),
researcher(havilland,olive,expertise(5,chemistry))).
Given this information, write Prolog rules (and any additional predicates required) that can be used to return the following:
the first name and surname of any leader whose crew members number more than one and who all have the same surname. [4 marks]
This is the solution I presently have using recursion, though it's unnecessarily inefficient as for every member of the list, it compares that member to every other member. So, as the correct list is four members long, it returns 'jack maine' four times.
surname(researcher(S,_,_),S).
checkSurname([],Surname):-
Surname==Surname. % base case
checkSurname([Researcher|List],Surname):-
surname(Researcher,SameSurname),
Surname == SameSurname,
checkSurname(List,SameSurname).
q4(Forename,Surname):-
group(Crew,researcher(Surname,Forename,_),_),
length(Crew,Length),
Length > 1,
member(researcher(SameSurname,_,_),Crew),
checkSurname(Crew,SameSurname).
How could I do this without the duplicate results and without redundantly comparing each member to every other member each time? For every approach I've taken I am snagged each time with 'SameSurname' being left as a singleton, hence having to force use of it twice in the q4 predicate.
Current output
13 ?- q4(X,Y).
X = jack,
Y = maine ; x4
A compact and efficient solution:
q4(F, S) :-
group([researcher(First,_,_), researcher(Second,_,_)| Crew], researcher(S, F, _), _),
\+ (member(researcher(Surname, _, _), [researcher(Second,_,_)| Crew]), First \== Surname).
Example call (resulting in a single solution):
?- q4(X,Y).
X = jack,
Y = maine.
You are doing it more complicated than it has to be. Your q4/2 could be even simpler:
q4(First_name, Surname) :-
group(Crew, researcher(Surname, First_name, _E), _A),
length(Crew, Len), Len > 1,
all_same_surname(Crew).
Now you only need to define all_same_surname/1. The idea is simple: take the surname of the first crew member and compare it to the surnames of the rest:
all_same_surname([researcher(Surname, _FN, _E)|Rest]) :-
rest_same_surname(Rest, Surname).
rest_same_surname([], _Surname).
rest_same_surname([researcher(Surname, _FN, _E)|Rest), Surname) :-
rest_same_surname(Rest, Surname).
(Obviously, all_same_surname/1 fails immediately if there are no members of the crew)
This should be it, unless I misunderstood the problem statement.
?- q4(F, S).
F = jack,
S = maine.
How about that?
Note: The solution just takes the most straight-forward approach to answering the question and being easy to write and read. There is a lot of stuff that could be done otherwise. Since there is no reason not to, I used pattern matching and unification in the heads of the predicates, and not comparison in the body or extra predicates for extracting arguments from the compound terms.
P.S. Think about what member/2 does (look up its definition in the library, even), and you will see where all the extra choice points in your solution are coming from.
Boris did answer this question already, but I want to show the most concise solution I could come with. It's just for the educational purposes (promoting findall/3 and maplist/2):
q4(F, S) :-
group(Crew, researcher(S, F, _), _),
findall(Surname, member(researcher(Surname, _, _), Crew), Surnames),
Surnames = [ First, Second | Rest ],
maplist(=(First), [ Second | Rest ]).
Hello I want to make a program in Prolog, that given a list of numbers and a number, it appends all the concurences of position of the number in a second list.
For example for the list (5,10,4,5,6,5) and number =5 the new list should be
(1,4,6)
here is my code so far
positions(X, [X|_],1).
positions(X, [P|T], N) :- positions(X, T, N1), N is N1+1.
find(X, [H|T] ,Z) :-positions(X,[H|T],N) , append([],N,Z).
the positions returns the first concurrence of X in the list, but I don't know how to proceed. Can you help me?
If it's not an assignment, then you can benefit from using the built-ins findall/3 and nth1/3:
?- findall(Nth, nth1(Nth, [5,10,4,5,6,5], 5), Nths).
Nths = [1, 4, 6].
Taking just the nth1 phrase, and running that, you can see it is backtracking and finding multiple solutions, then we just use findall to collect them into a list.
?- nth1(Nth, [5,10,4,5,6,5], 5).
Nth = 1 ;
Nth = 4 ;
Nth = 6.
nth1/3, when using a variable for the first parameter, is saying 'give me a list index where where the 3rd parameter is found in the list of the second parameter.
You have some good ideas, but I would suggest a couple things:
1) In Prolog, it can be beneficial to give variables meaningful names
2) Use an accumulator and you will only need positions and append
3)Use a different base case
positions([Num|List],Num,[Index|SubResult],Index) :- Index2 is Index+1,
positions(List,Num,SubResult,Index2).
positions([NotNum|List],Num,Result,Index) :- NotNum \= Num,
Index2 is Index+1,
positions(List,Num,Result,Index2).
positions([],Num,[],Index).
In our first general case, we can see the numbers match, so we go find how many results are in our sublist, which we will call the SubResult and then push the current index on to our SubResult
The next general case, the numbers do not unify, and our Result IS the SubResult, so let's call them the same thing.
In our final case (the base case) we can see the list is empty, in this case we return an empty list as we cannot match against an empty list.
You can see that the above rules are order-independent, which is something very valuable in Prolog. This means you can arrange the rules in any order, and the semantics of your Prolog program remain unchanged. Using unification to achieve this will prevent future pain in debugging.
We can wrap our predicate in the following way
positions(Num, List, Positions) :- positions(List, Num, Positions, 1).
This will allow for queries of positions(5,[5,10,4,5,6,5],Positions).
I'm very new to Prolog and am trying to figure out exactly what is happening with this (function?) that takes out the 2nd to last element in a list.
remove([],[]).
remove([X],[X]).
remove([_,X],[X]).
remove([X|Xs], [X|Ys]) :-
Xs = [_,_|_],
remove(Xs,Ys).
I'm familiar with pattern matching, as I've done a little work in SML. The first one is clearly the base case, returning the empty list when we break it down. The second returns the same variable when there is only one left. The third looks as if it returns the last element, disregarding the 2nd to last? As for the inductive case, it will attach the head of the list to the new list if ...... (This is where I get completely lost). Could anyone explain what's happening in this function so I can have a better understanding of the language?
Elaborating on CapelliC's explanation:
remove([],[]).
An empty list is an empty list with the second-to-last element removed.
remove([X],[X]).
A single-element list is itself with the second-to-last element removed.
remove([_,X],[X]).
A two-element list with the second to last element removed is a list of one element consisting of the last element of the two-element list.
remove([X|Xs], [X|Ys]) :-
Xs = [_,_|_],
remove(Xs,Ys).
The second list is the first list with the second element removed, and share the same first element, IF:
The tail of the first list consists of at least two elements, AND
The tail of the second list is the tail of the first list with the second to last element removed
A set of clauses is a predicate, or procedure.
All first three are base cases, and the recursive one copies while there are at least 3 elements in the first list.
I would describe the behaviour like 'removes pre-last element'.
So, how to declaratively read
remove([X|Xs], [X|Ys]) :-
Xs = [_,_|_],
remove(Xs,Ys).
Most important is that you first realize what the :- actually means.
Head :- Body.
It means: Whenever Body holds, we can conclude that also Head holds. Note the rather unintuitive direction of the arrow. It goes right-to-left. And not left-to-right, as often written informally when you conclude something. However, the error points into the direction of what we get "out of it".
To better see this, you can enter Body as a query!
?- Xs = [_,_|_], remove(Xs,Ys).
Xs = [A, B], Ys = [B]
; Xs = [A, B, C], Ys = [A, C]
; ... .
So we get all answers, except those where Xs has less than two elements.
Please note that procedurally, things happen exactly in the other direction - and that is very confusing to beginners. Even more so, since Prolog uses two "non-traditional" features: chronological backtracking, and variables - I mean real variables, meaning all possible terms - not these compile time constructs you know from imperative and functional languages. In those languages variables are holders for runtime values. Concrete values. In Prolog, variables are there at runtime, too. For more to this, see Difference between logic programming and functional programming
There is also another issue, I am not sure you understood. Think of:
?- remove(Xs, [1,2]).
Xs = [1, A, 2]
; false.
What is removed here? Nothing! Quite the contrary, we are adding a further element into the list. For this reason, the name remove/2 is not ideal in Prolog - it reminds us of command oriented programming languages that enforce that some arguments are given and others are computed. You might at first believe that this does not matter much, after all it's only a name. But don't forget that when programming you often do not have the time to think through all of it. So a good relational name might be preferable.
To find one, start with just the types: list_list/2, and then refine list_removed/2 or list__without_2nd_last/2.
Annotated:
remove( [] , [] ) . % removing the 2nd last element from the empty list yields the empty list
remove( [X] , [X] ) . % removing the 2nd last element from a 1-element list yields the 1-element list.
remove( [_,X] , [X] ) . % removing the 2nd last element from a 2-element list yields the tail of the 2-element list
remove( [X|Xs] , [X|Ys] ) :- % for any other case...
Xs = [_,_|_], % * if the tail contains 2 or more elements, the list is 3 elements or more in length
remove(Xs,Ys). % we simply prepend the head of the list to the result and recurse down.
It should be noted that the last clause could re-written a tad more clearly (and a little more succinctly) as:
remove( [X1,X2,X3|Xs] , [X1|Ys] ) :- % for any other case (a list of length 3 or more)
remove([X2,X3|Xs],Ys). % we simply prepend the head of the list to the result and recurse down.
Or as
remove( [X1|[X2,X3|Xs]] , [X1|Ys] ) :- % for any other case (a list of length 3 or more)
remove([X2,X3|Xs],Ys). % we simply prepend the head of the list to the result and recurse down.