It's my first time with Prolog programming and I have issues with gnome sort, I've read it's similar to insert and bubble sort, but I have no idea how to connect them.
gnome_sort(List,Sorted):-g_sort(List,[],Sorted).
g_sort([],Acc,Acc).
g_sort([H|T],Acc,Sorted):-insert(H,Acc,NAcc),g_sort(T,NAcc,Sorted).
last_element(X,[X]).
last_element(X,[_|O]):-last_element(X,O).
insert(X, last_element(P,[Y|T]),[Y|NT]):-X>P,g_sort(Y,P,NT).
insert(X,[Y|T],[X,Y|T]):-X=<Y.
insert(X,[],[X]).
I have something like this but it doesn't work :((((((((
Note that what you're implementing is not the real Gnome sort but rather something more like the "optimization" noted on the Wikipedia page which is a completely different algorithm that is an insertion sort and has nothing to do with Gnome sort itself.
Anyway, your general approach works, but your implementation of insert/3 is broken. This is a predicate that should only insert an element into a list that is already assumed to be sorted. This predicate should never refer to g_sort: You don't want to freshly sort a list, only insert one element. You also don't need to refer to refer to the list's last element.
The only choice that insert/3 needs to make in a given situation is: is X greater than the first element of the sorted list or not? You already handle two cases correctly: Where the list is empty, and where X =< Y.
Only one clause of your insert/3 needs to change:
insert(X, [Y | Ys], [Y | XYs]) :-
X > Y,
insert(X, Ys, XYs).
If X > Y, this "skips" Y and looks for the correct insertion position in the rest of the list.
For comparison, your clause looked like this:
insert(X, last_element(P,[Y|T]),[Y|NT]):-X>P,g_sort(Y,P,NT).
I'm not sure what you were trying to do here, maybe you were going for a "function call" to last_element? Remember that Prolog has no function calls. If you write something like last_element(A, B) in a clause head, that refers to a term of the shape last_element(A, B), not to a "result" of "evaluating" the term last_element(A, B).
(Also, do you see how I put each goal on a separate line and used spaces around operators and after commas? You should do that too. Prolog is already hard enough to read when it's nicely formatted, you shouldn't make it even harder with bad formatting.)
For whatever it's worth, a real Gnome sort in Prolog would look like this:
gnomesort(List, Sorted) :-
gnomesort([], List, Sorted).
gnomesort(Left, [], Sorted) :-
reverse(Left, Sorted).
gnomesort([], [R | Rs], Sorted) :-
gnomesort([R], Rs, Sorted).
gnomesort([L | Ls], [R | Rs], Sorted) :-
R #>= L,
gnomesort([R, L | Ls], Rs, Sorted).
gnomesort([L | Ls], [R | Rs], Sorted) :-
R #< L,
gnomesort(Ls, [R, L | Rs], Sorted).
Related
I have written a Prolog code to find the cardinality of a list ie number of distinct elements. It gives correct output but it runs multiple times and I cant seem to get my head around it. I have used the debugger but cant understand whats wrong
member(A, [A|_]).
member(A, [_|L]) :- member(A, L).
crdnlty([],0).
crdnlty([A|R],N) :-
(
\+ member(A, R),
crdnlty(R, N1),
N is N1+1
);
(
member(A, R),
crdnlty(R, N)
).
member checks if A is present in the remaining list.
if its not present ie it is the last occurrence of that element cardinality is increased by 1.
for example if i run the query
crdnlty([1,2,1,1], N).
it returns
N = 2 ;
N = 2 ;
false.
but it should return
N = 2 ;
false.
This is not answer but just a testing suggestion that doesn't fit in a comment.
Besides the unwanted duplicated solution, there's also the question on how to test the predicate. A simple alternative solution is to use the ISO Prolog standard predicate sort/2 and the de facto standard predicate length/2. The alternative solution could be:
cardinality(List, Cardinality) :-
sort(List, Sorted),
length(Sorted, Cardinality).
We can use this alternative solution to define a property that your solution must comply with that allows to QuickCheck your solution (ignoring for now the unwanted non-determinism):
property(List) :-
once(crdnlty(List, C)),
sort(List, S),
length(S, C).
Using the QuickCheck implementation provided by Logtalk's lgtunit tool (which you can run in most Prolog systems; in this example I will be using GNU Prolog):
$ gplgt
...
| ?- {lgtunit(loader)}.
...
% (0 warnings)
(578 ms) yes
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
% 2000 random tests passed
(1589 ms) yes
Of course, QuickCheck can show bugs but cannot prove their absence. That said, a distinctive feature of Logtalk's QuickCheck implementation is that it tries trivial/corner cases for the specified types before generating random values. This help in ensuring that the random testing will not miss obvious test cases (as we illustrate next).
What happens if we test instead the solution provided by Scott Hunter?
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
* quick check test failure (at test 1 after 0 shrinks):
* property([])
no
In fact, his solution doesn't take into account that the list may be empty. Assuming that's considered a bug, adding the missing clause:
crdnlty([], 0).
Re-testing:
| ?- lgtunit::quick_check(property(+list(integer)), [n(2000)]).
% 2000 random tests passed
(1509 ms) yes
It might be better to build a list of distinct elements & yield its length for the cardinality:
crdnlty([A|R],N) :- distinct(R,N,[A],1).
% distinct(L,N,DL,DN): There are N distinct values in list L+DL,
% assuming there are DN distinct values in list DL alone.
distinct([],N,_,N).
distinct([A|R],N,DL,DN) :-
(
\+ member(A, DL),
DN1 is DN+1,
distinct(R, N, [A|DL], DN1)
);
(
member(A, DL),
distinct(R, N, DL, DN)
).
I am new to prolog, I am just learning about lists and I came across this question. The answer works perfect for a list of integers.
minimo([X], X) :- !.
minimo([X,Y|Tail], N):-
( X > Y ->
minimo([Y|Tail], N)
;
minimo([X|Tail], N)
).
How can I change this code to get the smallest int from a mixed list?
This
sint([a,b,3,2,1],S)
should give an answer:
S=1
you could just ignore the problem, changing the comparison operator (>)/2 (a binary builtin predicate, actually) to the more general (#>)/2:
minimo([X], X) :- !.
minimo([X,Y|Tail], N):-
( X #> Y ->
minimo([Y|Tail], N)
;
minimo([X|Tail], N)
).
?- minimo([a,b,3,2,1],S).
S = 1.
First of all, I don't think the proposed implementation is very elegant: here they pass the minimum found element thus far by constructing a new list each time. Using an additional parameter (we call an accumulator) is usually the way to go (and is probably more efficient as well).
In order to solve the problem, we first have to find an integer. We can do this like:
sint([H|T],R) :-
integer(H),
!,
sint(T,H,R).
sint([_|T],R) :-
sint(T,R).
So here we check if the head H is an integer/1. If that is the case, we call a predicate sint/3 (not to be confused with sint/2). Otherwise we call recursively sint/2 with the tail T of the list.
Now we still need to define sint/3. In case we have reached the end of the list [], we simply return the minum found thus far:
sint([],R,R).
Otherwise there are two cases:
the head H is an integer and smaller than the element found thus far, in that case we perform recursion with the head as new current minimum:
sint([H|T],M,R):
integer(H),
H < M,
!,
sint(T,H,R).
otherwise, we simply ignore the head, and perform recursion with the tail T.
sint([_|T],M,R) :-
sint(T,M,R).
We can put the recursive clauses in an if-then-else structure. Together with the earlier defined predicate, the full program then is:
sint([H|T],R) :-
integer(H),
!,
sint(T,H,R).
sint([_|T],R) :-
sint(T,R).
sint([],R,R).
sint([H|T],M,R):
(
(integer(H),H < M)
-> sint(T,H,R)
; sint(T,M,R)
).
The advantage of this approach is that filtering and comparing (to obtain the minimum) is done at the same time, so we only iterate once over the list. This will usually result in a performance boost since the "control structures" are only executed once: more is done in an iteration, but we only iterate once.
We can generalize the approach by making the filter generic:
filter_minimum(Filter,[H|T],R) :-
Goal =.. [Filter,H],
call(Goal),
!,
filter_minimum(Filter,T,H,R).
filter_minimum(Filter,[_|T],R) :-
filter_minimum(Filter,T,R).
filter_minimum(_,[],R,R).
filter_minimum(Filter,[H|T],M,R) :-
Goal =.. [Filter,H],
(
(call(Goal),H < M)
-> filter_minimum(Filter,T,H,R)
; filter_minimum(Filter,T,M,R)
).
You can then call it with:
filter_minimum(integer,[a,b,3,2,1],R).
to filter with integer/1 and calculate the minimum.
You could just write a predicate that returns a list with the numbers and the use the above minimo/2 predicate:
only_numbers([],[]).
only_numbers([H|T],[H|T1]):-integer(H),only_numbers(T,T1).
only_numbers([H|T],L):- \+integer(H),only_numbers(T,L).
sint(L,S):-only_numbers(L,L1),minimo(L1,S).
I'm working on defining a predicate min_in_list/2 that would find the smallest value on a list. If there is less than 2 elements in the list the program should output "Error: There are not enough elements in the list" and if an element on the list is not a digit Eg. [2,a,3]. The program should output "Error: The element is not a number". I created a predicate that would find the smallest value and checking if the list has less than two values but I'm having problem on checking if an element of a list is not a digit and outputting the error message
My code:
min_in_list([Min],_):- write('ERROR: List has fewer than two elements.').
min_in_list([],_):- write('ERROR: List has fewer than two elements.').
min_in_list([Min,_],Min).
min_in_list([H,K|T],M) :-
H =< K,
min_in_list([H|T],M).
min_in_list([H,K|T],M) :-
H > K,
min_in_list([K|T],M).
The test you're looking for is number/1, which tells you whether a value is a number or not. My final code looks like this:
min_in_list([], _) :- domain_error(not_empty_list, []).
min_in_list([X], _) :- domain_error(not_single_item_list, [X]).
min_in_list([X,Y|Rest], Min) :- min_in_list(X, [Y|Rest], Min).
min_in_list(Min, [], Min) :- !.
min_in_list(Min, [X|Rest], FinalMin) :-
( number(X) ->
(NewMin is min(Min, X),
min_in_list(NewMin, Rest, FinalMin))
;
type_error(number, X)
).
I'm still not entirely sure how to format a condition like this, but splitting it into separate predicates seems like an awful waste. Hopefully someone will come along and tell me how to format this so that it is attractive.
If you are using SWI-Prolog, you can simplify things using must_be/2:
min_in_list(Min, [], Min).
min_in_list(Min, [X|Rest], FinalMin) :-
must_be(number, X),
NewMin is min(Min, X),
min_in_list(NewMin, Rest, FinalMin).
The simplest solution can be:
list(Min, [Min]).
list(Min, [H|T]) :- list(PMin, T), Min is min(H, PMin).
However it must be note, that it will be stack overhead on big arrays.
Can someone please help me in transforming this to match this updated requirement?
Define a predicate strikeDuplicates(X,Y) that succeeds if and only the list Y would
be obtained if one were to remove the second and subsequent occurrences of each element
from list X. (You might read strikeDuplicates (X,Y) as list X without duplicates
is list Y.) The strikeDuplicates/2 predicate need not work well when X is an
unbound variable.
I asked a similar question two days ago asking this:
Define a predicate strike(X,Y,Z) that succeeds if and only if the list Z would be
obtained if one were to remove all occurrences of element X from list Y. The
strike/3 predicate need not work well when Y is an unbound variable.
No one helped me so I had to do it by myself. That answer was this:
strike( _ , [] , [] ) .
strike( X , [X|T] , Z ) :- strike(X,T,Z) .
strike( X , [A|T] , [A|Z] ) :- dif(X,A) , strike(X,T,Z) .
dif(X,A).
A simple solution that doesn't preserve order is:
strike_duplicates([], []).
strike_duplicates([X| Xs], List) :-
( member(X, Xs) ->
strike_duplicates(Xs, List)
; List = [X| Tail],
strike_duplicates(Xs, Tail)
).
To preserve order, you need to keep track of the elements found so far while you traverse the list. A solution would be:
strip_duplicates(List, Set) :-
strip_duplicates(List, [], Set).
strip_duplicates([], _, []).
strip_duplicates([X| Xs], Found, List) :-
( member(X, Found) ->
strip_duplicates(Xs, Found, List)
; List = [X| Tail],
strip_duplicates(Xs, [X| Found], Tail)
).
The predicate member/2 is usually either a built-in predicate or available as a library predicate. Check your Prolog system documentation if necessary.
Well, the easy way would be to use the built-in predicate setof/3, but I suspect that's not what your professor wants.
Think about the problem for a second or two. A clear problem statement is often helpful (and in Prolog is often the solution itself):
To make the source list a set (unique elements) instead of a bag (allows duplication), you'll have to
Iterate over the source list
Track items you've already seen (the 'visited' list)
Add each item to the visited list only if the visited list doesn't already contain it.
Once you've done that you've got the desired result.
Here's a hint: a very common prolog idiom is the use of helper predicates that carry with it an accumulator. Often the helper predicate has the same functor, but a different arity. For example, to sum the values in a list (sum/2) we can use a helper sum/3 that carries an accumulator, seeded with 0:
sum(Xs,N) :- sum(Xs,0,N).
sum([],S,S).
sum([N|Ns],T,S) :-
T1 is T+N,
sum(Ns,T1,S)
.
You'll notice how unfication with the result is deferred until the final value has been computed.
You need to do something like that but using as an accumulator an [empty] list that will be extended with the unique values you discover.
Another hint: the built-in predicate member/2 will check if a term is a member of a list. It's written
member(X,[X|Xs]).
member(X,[_|Xs]) :- member(X,Xs).
So member(2,[1,2,3]) is true whilst member(2,[1,3]) is false.
Conversely, one can use member/2 to successively return each element of a list via backtracking: member(X,[1,2,3]) produces
X = 1 ;
X = 2 ;
X = 3 ;
false
Given those two notions, you should be able to figure out the solution. Come back and show us your code and we can help you. There is one other little gotcha, but I'm sure you'll figure it out.
I starting to study for my upcoming exam and I'm stuck on a trivial prolog practice question which is not a good sign lol.
It should be really easy, but for some reason I cant figure it out right now.
The task is to simply count the number of odd numbers in a list of Int in prolog.
I did it easily in haskell, but my prolog is terrible. Could someone show me an easy way to do this, and briefly explain what you did?
So far I have:
odd(X):- 1 is X mod 2.
countOdds([],0).
countOdds(X|Xs],Y):-
?????
Your definition of odd/1 is fine.
The fact for the empty list is also fine.
IN the recursive clause you need to distinguish between odd numbers and even numbers. If the number is odd, the counter should be increased:
countOdds([X|Xs],Y1) :- odd(X), countOdds(Xs,Y), Y1 is Y+1.
If the number is not odd (=even) the counter should not be increased.
countOdds([X|Xs],Y) :- \+ odd(X), countOdds(Xs,Y).
where \+ denotes negation as failure.
Alternatively, you can use ! in the first recursive clause and drop the condition in the second one:
countOdds([X|Xs],Y1) :- odd(X), !, countOdds(Xs,Y), Y1 is Y+1.
countOdds([X|Xs],Y) :- countOdds(Xs,Y).
In Prolog you use recursion to inspect elements of recursive data structs, as lists are.
Pattern matching allows selecting the right rule to apply.
The trivial way to do your task:
You have a list = [X|Xs], for each each element X, if is odd(X) return countOdds(Xs)+1 else return countOdds(Xs).
countOdds([], 0).
countOdds([X|Xs], C) :-
odd(X),
!, % this cut is required, as rightly evidenced by Alexander Serebrenik
countOdds(Xs, Cs),
C is Cs + 1.
countOdds([_|Xs], Cs) :-
countOdds(Xs, Cs).
Note the if, is handled with a different rule with same pattern: when Prolog find a non odd element, it backtracks to the last rule.
ISO Prolog has syntax sugar for If Then Else, with that you can write
countOdds([], 0).
countOdds([X|Xs], C) :-
countOdds(Xs, Cs),
( odd(X)
-> C is Cs + 1
; C is Cs
).
In the first version, the recursive call follows the test odd(X), to avoid an useless visit of list'tail that should be repeated on backtracking.
edit Without the cut, we get multiple execution path, and so possibly incorrect results under 'all solution' predicates (findall, setof, etc...)
This last version put in evidence that the procedure isn't tail recursive. To get a tail recursive procedure add an accumulator:
countOdds(L, C) :- countOdds(L, 0, C).
countOdds([], A, A).
countOdds([X|Xs], A, Cs) :-
( odd(X)
-> A1 is A + 1
; A1 is A
),
countOdds(Xs, A1, Cs).