Custom data structure syntax in Prolog - data-structures

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.

Related

Does the Prolog symbol :- mean Implies, Entails or Proves?

In Prolog we can write very simple programs like this:
mammal(dog).
mammal(cat).
animal(X) :- mammal(X).
The last line uses the symbol :- which informally lets us read the final fact as: if X is a mammal then it is also an animal.
I am beginning to learn Prolog and trying to establish which of the following is meant by the symbol :-
Implies (⇒)
Entails (⊨)
Provable (⊢)
In addition, I am not clear on the difference between these three. I am trying to read threads like this one, but the discussion is at a level above my capability, https://math.stackexchange.com/questions/286077/implies-rightarrow-vs-entails-models-vs-provable-vdash.
My thinking:
Prolog works by pattern-matching symbols (unification and search) and so we might be tempted to say the symbol :- means 'syntactic entailment'. However this would only be true of queries that are proven to be true as a result of that syntactic process.
The symbol :- is used to create a database of facts, and therefore is semantic in nature. That means it could be one of Implies (⇒) or Entails (⊨) but I don't know which.
Neither. Or, rather if at all, then it's the implication. The other symbols are above, that is meta-language. The Mathematics Stack Exchange answers explain this quite nicely.
So why :- is not that much of an implication, consider:
p :- p.
In logic, both truth values make this a valid sentence. But in Prolog we stick to the minimal model. So p is false. Prolog uses a subset of predicate logic such that there actually is only one minimal model. And worse, Prolog's actual default execution strategy makes this an infinite loop.
Nevertheless, the most intuitive way to read LHS :- RHS. is to see it as a way to generate new knowledge. Provided RHS is true it follows that also LHS is true. This way one avoids all the paradoxa related to implication.
The direction right-to-left is a bit counter intuitive. This direction is motivated by Prolog's actual execution strategy (which goes left-to-right in this representation).
:- is usually read as if, so something like:
a :- b, c .
reads as
| a is true if b and c are true.
In formal logic, the above would be written as
| a ← b ∧ c
Or
| b and c imply a

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.

Sort tuples in Prolog

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.

binary predicate to square list and sublists in Prolog

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.

Resources