How to make predicate repeat N number of times in Prolog? - list

I have a number of lists containing letters and I have written a predicate that checks whether or not there are duplicates present in one of these given lists:
noDuplicates([]).
noDuplicates([H|T]):-
not(member(H, T)),
noDuplicates(T).
I have 10 lists and I want to know if there are no duplicates in any of them, so I made them into sublists of one big list, something like:
[[A,B,C], [C,A,D], [E,F,G]...]]
(So there can be duplicates in the big list, but not the individual sublists).
I get that I have to do the duplicates test 10 times; once for every sublist, but how do I write this in Prolog? I could probably write it down 10 times, but my guess is I can use recursion to make prolog repeat itself until all sublists have been checked.
So basically: I want this predicate to repeat itself N times, until N is 10. I'm really struggling with it though. Does anyone have any idea on what to do?

Let us generalize the question as follows:
You have a predicate p/1 that expresses what you want for a single list.
Thus, to lift this definition to a list of such lists, you can define a predicates ps/1 as follows:
ps([]).
ps([L|Ls]) :-
p(L),
ps(Ls).
Every time you see this pattern, you can use maplist/2. That is, the above is equivalent to:
ps(Ls) :- maplist(p, Ls).
The goal maplist(p, Ls) is true iff p holds for each element L of Ls.
Note that it will limit your understanding of Prolog if you think in terms of "looping" and "repeating". These are imperative notions and only make sense when the list is already fully instantiated. However, from Prolog, we expect more than that: We expect a full-fledged relation to also generate lists for which the relation holds. And in such cases, there is nothing to "repeat" yet: We start from nothing, and ask Prolog what solutions there are in general.
Thus, think in terms of describing when the relation ps/1 holds for lists of lists:
It holds for the empty list [].
It holds for the list [L|Ls] if our initial predicate (p/1) holds for L, and ps/1 holds for the remaining list Ls.
This declarative reading is applicable in all directions, no matter how many list elements are already instantiated, if any. It works for 10 lists just as well as for zero and 50.

Related

Mutating elements of a list in Prolog

I am supposed to write a rule in SWI Prolog, which takes a list of characters as input and then replaces each letter by a random other character with a probability of 0.01.
Example:
?- mutate([a,b,c,d,e,f,g],MutatedList).
MutatedList = [a,b,c,a,e,f,g].
Can anyone tell me how that could be implemented? I am totally clueless so far about how this could work out in Prolog.
Thanks to anyone who can help!^^
This is relatively easy. You can use maplist/3 to relate the elements of the lists in a pairwise way. (Take a look at some of my notes on maplist/3].
For each pair [InputItem,OutputItem] sampled from [InputList,OutputList], maplist/3 will call a predicate, call it choose(InputItem,OutputItem).
That predicate will relate InputItem to the same value, InputItem or to a randomly chosen character (atom of length 1), which can be generated by selecting it randomly from a list of characters. The choice on whether to perform mutation can be made using random_float/0 for example.
Of course, choose(InputItem,OutputItem) is not really a predicate (it is just called that way, both in name at runtime), as it does not behave "predicatly" at all, i.e. it will have different outcomes depending on the time of day. It's an Oracle getting information from a magic reservoir. But that's okay.
Now you are all set. Not more than 4 lines!

Prolog - how to generate list of specific length?

I'm doing this exercise for which I have to write a predicate randomnames/1 for generating a random list of three names (no duplicates allowed). I have a database with 10 names in it already and they all correspond to a number, for example: name(1, Mary).
I wrote a predicate for generating one random name:
randomname(Name) :-
random(0, 11, N), % generate random integer between 1 and 10.
name(N, Name).
My question would be: How do I get this in a list? And a list of exactly three elements at that?
I don't want to use too many built-ins. length/2 would be alright though. I think I might need it :)
Thanks a lot!
Edit: I figured I would first try to generate a list of three random numbers (the names can come later). I wrote this horribly wrong little thing:
numberlist([N|T]) :-
random(0, 11, N),
length([N|T], 3),
numberlist(T).
I know how to do this with a /2 predicate; when the user can just enter in the query that they want a list with three elements (numberlist(3,X).for example). But I'm can't seem to figure out how to write down in code that I always want a list of three numbers.
I was also thinking of using findall for generating my list, but again I don't know how to limit the length of the list to three random elements.
When describing lists in Prolog, it is often useful to first describe how a single element looks like.
For example, in your case, it seems you already have a predicate like random_name/1, and it describes a single element of the list you want to describe.
So, to describe a list consisting of three such elements, what about:
random_names([A,B,C]) :-
random_name(A),
random_name(B),
random_name(C).
This describes a list with three elements, and random_name/1 holds for each of these elements.

Prolog - Modifying and returning list

I want to define predicate which takes a list, adds an element to the list, let's say the number "1", and then returns the list.
I've found out I can add elements to a list using append/3, but I want to use in inside another predicate, thus why I want it to return "my modified list".
My object-oriented mindset tells me to ask the interpreter something like: ?-append(X,5,X). , so that it takes the list X, adds 5 to it, and returns "the new X", but I know that's not how unification works, so my mind is kinda in a glitch.
Can anyone please try to explain how something like this could be achievable?
You are already very close to the solution, so I only rephrase what you are beginning to sense already:
First, you cannot modify a list in pure Prolog.
Instead, you should think in terms of relations between entities. In your case, think in terms of relations between lists.
So, "adding the number 1" to a list is a relation between two lists, which could look like this:
list_with_one(Ls, [1|Ls]).
Note that this works in all directions! You can use it to:
generate answers
test particular cases
"reverse" the direction etc.
So, all you need to do in your case is to think in terms of relations between lists: One without an element, and how this relates to a different list with the element.
Obviously, these two lists will be indicated by different variables and different arguments.
Note in particular that append(X, 5, X) cannot hold: First of all, append/3 is meant to be a relation between lists, and 5 is not a list. Second, assuming you wrote for example append(Xs, [5], Xs), then this would be true if there where a list Xs such that if the element 5 were appended to Xs, the resulting list would again be Xs. Good luck finding such a list... Note also the naming convention to denote lists by letting the variable name end with an s.
It is also falls a bit short to blame this on your "object-oriented mindset", since you can have object oriented programming in Prolog too.
Although lists in Prolog cannot be modified, it is possible to add elements to the end of a list with an unspecified length. In this way, items can be "appended" to a list without creating another list:
:- initialization(main).
append_to_list(List,Item) :-
append_to_list(List,Item,0).
append_to_list(List,Item,Index) :-
% using SWI-Prolog's nth0 predicate
(nth0(Index,List,Check_Item),
var(Check_Item),
nth0(Index,List,Item));
(Next_Index is Index+1,
append_to_list(List,Item,Next_Index)).
main :-
A = [1,2,3|_],
append_to_list(A,4),
append_to_list(A,7),
writeln(A).
In this example, A becomes [1,2,3,4,7|_].

Reverse the last two elements of a list in Prolog

I am trying to write the following predicate in Prolog while not making use of append/3:
lastTwoReversed(List, ListOf2)
which succeeds exactly when ListOf2 contains the last and the second-to-last elements of List in that order (i.e. reversed).
However, I don't know where to start. Any help is appreciated.
You can write a simple recursive predicate with a base case pattern matching on a list consisting of two elements like so:
last_two_reversed([X,Y],[Y,X]).
Since this is probably homework, I think it's best if you try to write the recursive clause yourself.
Simply use the built-in predicate reverse/2:
last_two_reversed([A,B|T],[Y,X]) :-
reverse([A,B|T],[Y,X|_]).
This will fail for lists with strictly less than two elements. A sensible thing to do would be to make it succeed using those two additional rules:
last_two_reversed([],[]).
last_two_reversed([H],[H]).
First of all, the predicate should fail or succeed with empty list or list with only one element??
In mathematical logic the predicate should return true with empty list and one-element list, because there are no last and second to-last elements to reverse.
So if you want to succeed with empty or one element list you should first start with :
lastTwoReversed([],[]).
lastTwoReversed([X],[X]).
(else don't write the above rules).
Next as base you should write:
lastTwoReversed([X,Y],[Y,X]).
and finally for list of length 3 or greater:
lastTwoReversed([X,Y,Z|T],[X|T1]):-lastTwoReversed([Y,Z|T],T1).
Keep in mind that we write [X,Y,Z|T] to specify for list with 3 or more elements so that doesn't match the previous rules.

Prolog Recursion with lists

I am having a difficult time understand recursion in prolog. I can read examples and sometimes understand, but I mostly have a difficult time implementing them. For example, could someone code me how to find the summation all the elements in a list, and go through it? and tips on how to approach a question like this? Thanks!
A general "good" explanation is not possible, because a good explanation needs to link to the previous knoledgment of the person. I'm going, by example, assume you are able to made a "proof by induction".
Step1: Let start by the initial fact, "the sum of a set with a single element is the element itself". In prolog:
sum([A],A).
Step2: if the sum of a set Q is SQ, the sum of this set adding one element H is H+SQ. In prolog:
sum([H|Q],R) :- sum(Q,SQ), R is H+SQ.
thats all, you have the problem solved. But...
In general, we try to start by the most basic set, the empty one, so replace "step 1" that becames now: the sum of the elements of an empty set is 0:
sum([],0).
Finally, prolog is more efficiente if the rules are tail recursive (if the execution environment is not able to optimice by itself). That means a little change:
sum([],R,R).
sum([H|Q],SQ,R) :- T is SQ+H, sum(Q,T,R).
these rules can be understood as: Assume (assert) that sum of Q is SQ. In this case, sum of set Q plus an element H is SQ+H. The first one means, when there are no more elements in the pending set, the result is directly the acumulated sum.
Thinking recursively can be hard. See my answer to the question "Prolog programming - path way to a solution" for links to good resources on how to think recursively.
For instance, most recursive problems can be broken down into a few (1 or 2) special cases, and then, the general case. In your case — computing the sum of a list of numbers — one might look at it has having 1 or two special cases. First, you have to make a decision: What is the sum of an empty list? One might argue either that the sum of an empty list is zero, or that an empty list has no sum. Either is, arguable, a perfectly valid point-of-view.
In either event, the special cases are
[]. The empty list. The sum of the empty list is either 0, or nothing (in which case your predicate should fail.)
[100]. A list of length one. The sum of a list of length 1 is obviously that value of the first and only entry.
And the more general case:
[100,101,102]. The sum of a list of length greater than 1 can be computed by taking the value of the first item in the list and computing the sum of the remainder. Note that
The solution is defined in terms of itself, and
The problem is made smaller (by removing the 1st item from the list).
Eventually, the problem will degenerate into one of the special cases, right?
Given all that, let us suppose that we've decided that the sum of the empty list is to be 0. That means our 2nd special case (a single element list) goes away, leaving us with a solution that can be described as
The sum of an empty list is 0.
The sum of a non-empty list is computed by
removing the 1st item from the list,
computing the sum of the remaining items,
adding the value of the 1st item to the sum of the remainder.
And since prolog is a declarative language, our solution is going to be pretty much identical to the description of the solution:
sum_of_list( [] , 0 ) .
sum_of_list( [N|Ns] , S ) :-
sum_of_list(Ns,T) ,
S is T+N
.
The c