Sort tuples in Prolog - sorting

When I sort [(101,a),(42,b),(85,b)] is Prolog with sort([(101,a),(42,b),(85,b)],X). is get X = [ (42, b), (85, b), (101, a)]. But how come? Does Prolog recognize the tuples and sort them on the first element and then on the second element?

You should really simply look at the exact documentation of the Prolog you are using. In SWI-Prolog, for example, sorting is on "standard order". For compound terms (as you are using), it is first arity, then name, then recursively arguments. So in your case, yes, it is sorted first on first and then on second argument.
By the way, ISO sort should remove duplicates, not that you get surprised by it.
And strictly speaking, there are no "tuples" in Prolog. What you have there is the functor , with arity 2 (or, ,/2). Look at this:
2 ?- write_canonical((42, b)).
','(42,b)
true.

Your assumption seems reasonable. We can check some documentation, personally I like the documentation for ciao.
See page 235, then page 115. Notice you could also sort by keys.
You should be aware that some people consider using this kind of predicates (non-declarative) a bad practice. Basically there are two terms in this predicate, one must be grounded and the other one must not, so in fact this is a function and not a logical predicate. Those worried for the "purity" of logic programming would probably find a workaround not to use that.

Related

How to make a random list of a specific length without duplicates in prolog?

I'm trying to write a predicate randomnames/1 that generates a random list of three different names. The names are in a database and I already have a predicate for one random name:
name(1, Mary).
name(2, Pat).
name(3, James).
name(4, Bob).
name(5, Susan).
random_name(Name):-
random(0, 6, N),
name(N, Name).
To get this in a list, someone suggested I should do:
random_names([A,B,C]) :-
random_name(A),
random_name(B),
random_name(C).
The only problem with this is that it's possible to get duplicates in the list generated. I can't figure out how to fix that issue. I could write a new predicate for removing duplicates, but how would I substitute the duplicate with another variable then, so that the list still has three elements? And how would I even write the remove predicate when there isn't a clear head and tail in the random_names predicate?
When programming in Prolog, think in terms of conditions that your solutions must satisfy.
Currently, you have already figured out how to describe a list with three elements, where each element is a random name.
That's a good start, but not yet sufficient: In addition, you now want to describe the condition that the elements are pairwise distinct.
So, think about how to describe a list of three elements where all elements are pairwise distinct.
I give you a start, using dif/2 to express disequality of terms in a sound way (see prolog-dif):
three_distinct_elements([A,B,C]) :-
dif(A, B),
dif(A, C),
dif(B, C).
You may find a more general and more elegant way to describe this for lists with more than 3 elements. However, the above suffices to solve the task at hand.
So, it only remains to combine the predicates you already have, using for example:
three_distinct_random_names(Ls) :-
random_names(Ls),
three_distinct_elements(Ls).
This is simply the conjunction of conditions which you have already implemented. In total, solutions of this predicate will give you what you want: A list with three distinct random names.
However, the predicate may also fail (Exercise: Why?).
To try the predicate until it finds a solution, use for example repeat/0:
?- repeat, three_distinct_random_names(Ls).
There are also better ways to solve this. However, as a first approximation, I recommend to focus on good building-blocks, describing the conditions you want to satisfy.
I have a general comment on what you write:
I could write a new predicate for removing duplicates, but how would I substitute the duplicate with another variable then, so that the list still has three elements?
This is all worded very imperatively: You think here about "removing", "substituting" etc. To get the most out of Prolog, focus on describing the conditions that must hold for the solutions you want to find!
You want to find a list without duplicates? Describe what such a a list must look like. You want random names? Describe what such a name looks like, etc.
In case if you are using Swi-Prolog you can use very handy randseq/3 predicate which comes bundled with Swi. randseq/3 generates list of all distinct random numbers in range from 1 to N. After getting this list generated all that remains is mapping numbers to names:
name(1, 'Mary').
name(2, 'Pat').
name(3, 'James').
name(4, 'Bob').
name(5, 'Susan').
random_names(Names, Count) :-
% 5 is the amount of names available in database
randseq(Count, 5, L),
maplist(name, L, Names).
Usage examples:
?- random_names(Names, 3).
Names = ['Mary', 'James', 'Susan'].
?- random_names(Names, 5).
Names = ['Susan', 'Bob', 'James', 'Mary', 'Pat'].

The list [[a,b]|c] in Prolog

During my exploration of different ways to write down lists, I am intrigued by the following list [[a,b]|c] which appears in the book 'Prolog and Natural Language Analysis' by Pereira and Shieber (page 42 of the digital edition).
At first I thought that such a notation was syntactically incorrect, as it would have had to say [[a,b]|[c]], but after using write_canonical/1 Prolog returned '.'('.'(a,'.'(b,[])),c).
As far as I can see, this corresponds to the following tree structure (although it seems odd to me that structure would simply end with c, without the empty list at the end):
I cannot seem to find the corresponding notation using comma's and brackets though. I thought it would correspond to [[a,b],c] (but this obviously returns a different result with write_canonical/1).
Is there no corresponding notation for [[a,b]|c] or am I looking at it the wrong way?
As others have already indicated, the term [[a,b]|c] is not a list.
You can test this yourself, using the | syntax to write it down:
?- is_list([[a,b]|c]).
false.
You can see from write_canonical/1 that this term is identical to what you have drawn:
| ?- write_canonical([[a,b]|c]).
'.'('.'(a,'.'(b,[])),c)
In addition to what others have said, I am posting an additional answer because I want to explain how you can go about finding the reason of unexpected failures. When starting with Prolog, you will often ask yourself "Why does this query fail?"
One way to find explanations for such issues is to generalize the query, by using logical variables instead of concrete terms.
For example, in the above case, we could write:
?- is_list([[A,b]|c]).
false.
In this case, I have used the logical variable A instead of the atom a, thus significantly generalizing the query. Since the generalized query still fails, some constraint in the remaining part must be responsible for the unexpected failure. We this generalize it further to narrow down the cause. For example:
?- is_list([[A,B]|c]).
false.
Or even further:
?- is_list([[A,B|_]|c]).
false.
And even further:
?- is_list([_|c]).
false.
So here we have it: No term that has the general form '.'(_, c) is a list!
As you rightly observe, this is because such a term is not of the form [_|Ls] where Ls is a list.
NOTE: The declarative debugging approach I apply above works for the monotonic subset of Prolog. Actually, is_list/1 does not belong to that subset, because we have:
?- is_list(Ls).
false.
with the declarative reading "There is no spoon list." So, it turns out, it worked only by coincidence in the case above. However, we could define the intended declarative meaning of is_list/1 in a pure and monotonic way like this, by simply applying the inductive definition of lists:
list([]).
list([_|Ls]) :- list(Ls).
This definition only uses pure and monotonic building blocks and hence is monotonic. For example, the most general query now yields actual lists instead of failing (incorrectly):
?- list(Ls).
Ls = [] ;
Ls = [_6656] ;
Ls = [_6656, _6662] ;
Ls = [_6656, _6662, _6668] .
From pure relations, we expect that queries work in all directions!
I cannot seem to find the corresponding notation using comma's and brackets though.
There is no corresponding notation, since this is technically speaking not a real list.
Prolog has syntacical sugar for lists. A list in Prolog is, like a Lisp list, actually a linked list: every element is either an empty list [], or a node .(H,T) with H the head and T the tail. Lists are not "special" in Prolog in the sense that the intepreter handles them differently than any other term. Of course a lot of Prolog libraries do list processing, and use the convention defined above.
To make complex lists more convenient, syntactical sugar was invented. You can write a node .(H,T) like [H|T] as well. So that means that in your [[a,b]|c]. We have an outer list, which has one node .(H,c) and the ? is another list, with two nodes and an empty list H = .(a,.(b,[])).
Technically speaking I would not consider this a "real" list, since the tail of a list should have either another node ./2, or an empty list.
You can however use this with variables like: [[a,b]|C] in order to unify the tail C further. So here we have some sort of list with [a,b] as first element (so a list containing a list) and with an open tail C. If we later for instance ground C to C = [], then the list is [[a,b]].

How to use difference lists in a Prolog interpreter

When I was writing down this question on an empty list as a difference list I wanted to test what I knew about those structures. However, when I tried something as simple as comparing different notations it seemed that I was wrong and that I did not understand what is actually going on with difference lists.
?- L = [a,b,c|[d,e]]-[d,e], L = [a,b,c].
false % expected true
I tested this on SWI-Prolog as well as SICStus. I verified the notation as this is how it is written in Bratko's Prolog Programming for AI, page 210, but apparently unification is not possible. Why is that? Don't these notations have the same declarative meaning?
I think you have the idea that the Prolog interpreter treats difference lists as something special. That is not the case: Prolog is not aware of the concept of a difference list (nor of nearly every concept except some syntactical sugar). He only sees:
L=-( |(a, |(b, |(c, |(d, |(e, []))))), |(d, |(e, [] )))
where -/2 and |/2 are functors, and a, b, c, d, e and [] are constants.
Difference lists are simply a programming technique (like for instance dynamic programming is a technique as well, the compiler cannot detect nor treat dynamic programming programs differently). It is used to efficiently unify a (partially) ununified part deep in an expression.
Say you want to append/3 two lists. You can do this as follows:
%append(A,B,C).
append([],L,L).
append([H|T],L,[H|B]) :-
append(T,L,B).
But this runs in O(n): you first need to iterate through the entire first list. If that list contains thousands of elements, it will take a lot of time.
Now you can define yourself a contract that you will feed an append_diff/3 not only the list, but a tuple -(List,Tail) where List is a reference to the beginning of the list, and Tail is a reference to the end of the not unified list. Examples of structures that fulfill this requirement are Tail-Tail, [a|Tail]-Tail, [1,4,2,5|Tail]-Tail.
Now you can effectively append_diff/3 in O(1) with:
append_diff(H1-T1,T1-T2,H1-T2).
Why? Because you unify the ununified tail of the first list with the second list. Now the ununified tail of the second lists becomes the tail of the final list. So take for instance:
append_diff([a|T1]-T1,[1,4,2,5|T2]-T2,L).
If you call the predicate, as you see above, T1 will unify with [1,4,2,5|T2], so now the first list collapses to [a|[1,4,2,5|T2]] or shorter [a,1,4,2,5|T2], since we also have a reference to T2, we can "return" (in Prolog nothing is returned), [a,1,4,2,5|T2]-T2: a new difference list with an open tail T2. But this is only because you give - a special meaning yourself: for Prolog - is simply -, it is not minus, it does not calculate a difference, etc. Prolog does not attach semantics to functors. If you would have used + instead of -, that would not have made the slightest difference.
So to return back to your question: you simply state to Prolog that L = -([a,b,c,d,e],[d,e]) and later state that L = [a,b,c]. Now it is clear that those two expressions cannot be unified. So Prolog says false.

Custom data structure syntax in Prolog

In Prolog, [H|T] is the list that begins with H and where the remaining elements are in the list T (internally represented with '.'(H, '.'(…))).
Is it possible to define new syntax in a similar fashion? For example, is it possible to define that [T~H] is the list that ends with H and where the remaining elements are in the list T, and then use it as freely as [H|T] in heads and bodies of predicates? Is it also possible to define e.g. <H|T> to be a different structure than lists?
One can interpret your question literally. A list-like data structure, where accessing the tail can be expressed without any auxiliary predicate. Well, these are the minus-lists which were already used in the very first Prolog system — the one which is sometimes called Prolog 0 and which was written in Algol-W. An example from the original report, p.32 transliterated into ISO Prolog:
t(X-a-l, X-a-u-x).
?- t(nil-m-e-t-a-l, Pluriel).
Pluriel = nil-m-e-t-a-u-x.
So essentially you take any left-associative operator.
But, I suspect, that's not what you wanted. You probably want an extension to lists.
There have been several attempts to do this, one more recent was Prolog III/Prolog IV. However, quite similar to constraints, you will have to face how to define equality over these operators. In other words, you need to go beyond syntactic unification into E-unification. The problem sounds easy in the beginning but it is frightening complex. A simple example in Prolog IV:
>> L = [a] o M, L = M o [z].
M ~ list,
L ~ list.
Clearly this is an inconsistency. That is, the system should respond false. There is simply no such M, but Prolog IV is not able to deduce this. You would have to solve at least such problems or get along with them somehow.
In case you really want to dig into this, consider the research which started with J. Makanin's pioneering work:
The Problem of Solvability of Equations in a Free Semi-Group, Akad. Nauk SSSR, vol.233, no.2, 1977.
That said, it might be the case that there is a simpler way to get what you want. Maybe a fully associative list operator is not needed.
Nevertheless, do not expect too much expressiveness from such an extension compared to what we have in Prolog, that is DCGs. In particular, general left-recursion would still be a problem for termination in grammars.
It is possible to extend or redefine syntax of Prolog with iso predicate
:- op(Precedence, Type, Name).
Where Precedence is a number between 0 and 1200, Type describe if the operatot is used postfix,prefix or infix:
infix: xfx, xfy, yfx
prefix: fx, fy
suffix: xf, yf
and finally name is the operator's name.
Operator definitions do not specify the meaning of an operator, but only describe how it can be used syntactically. It is only a definition extending the syntax of Prolog. It doesn't gives any information about when a predicate will succeed. So you need also to describe when your predicate succeeds. To answer your question and also give an example you could define :
:- op( 42, xfy, [ ~ ]).
where you declare an infix operator [ ~ ]. This doesn't means that is a representation of a list (yet). You could define clause:
[T ~ H]:-is_list([H|T]).
which matches [T~H] with the list that ends with H and where the remaining elements are in the list T.
Note also that it is not very safe to define predefined operators
like [ ] or ~ because you overwrite their existing functionality.
For example if you want to consult a file like [file]. this will
return false because you redefined operators.

Swi Prolog Relation

I am trying to write a relation split in Prolog that takes an integer N, a list L of integers, and other parameters, list L is flat. The relation split returns true if the list L can be divided into three subsets, such that the sum of the integers in each subset is strictly less than N. Otherwise, the relation returns false. This is the furthest I've gone so far:
split(list, list, list, list)
split([],[],[],[]).
list_sum([],0).
split([X|L], [X|L1], [X|L2], L3):-
list_sum([Head + Tail]),
list_sum>N,
!,
split(N, L,L1, L2, L3).
?- ERROR: toplevel: Undefined procedure: list_sum/2 (DWIM could not correct goal)
Any help and explanation is highly appreciated.
Basically your problem is that you need to go learn Prolog. I'm not kidding. You're going to fail your class if you think you can get away with this level of "not getting it" and pick up the rest on S.O.
What's that first line, a comment? Put the comment character there.
What is list_sum/2 doing there in the middle of your split/4 definition?
Unless you're trying to create some kind of difference list or destructuring arithmetic, [Head + Tail] will absolutely not do what you want.
What is list_sum>N supposed to mean on the next line? There is only one namespace in Prolog and the language is very, very dependent on getting your capitalization right. Being this sloppy does not bode well.
Why are you cutting on line 7?
Your last line is defining split/5 when the previous two rule heads (I think?) are defining split/4. This cannot be what you mean.
You're pattern-matching on line 4 requires that all three of the lists begin with the same value, which seems like a pretty special special-case considering you have no other in which you meaningfully examine the elements of the lists.
In my opinion this code is totally unsalvagable. Throw it away and start over. And read through a tutorial first.
To your exact question: you have not defined a predicate list_sum with two arguments in the "code" that you have shown. This is what the error is telling you.

Resources