How do i write a rule in prolog called countIt? - prolog

Write a function in Scheme or rules in Prolog called countlt that takes a list of numbers, L, and another number, N, and returns the count of numbers less than N in the list L.
?- countlt([6, 1, 9], 4, X).
X = 1.
?- countit([50, 27, 13], 1, X).
X = 0.

Something like this will solve your problem, if you are looking for a solution without that doesn't use any of the built-in or library predicates:
countlt([], _, 0).
countlt([A | B], N, X) :- ((N > A, countlt(B, N, T), X is T + 1); countlt(B, N, X)), !.
You could of course expand this into multiple lines but I find this solution more straightforward and with less tampering with cut operators.

Related

How to check how many elements you've already consumed in Prolog DCGs

Say I have these DCGs:
zorbs([H|T]) --> zorb(H), zorbs(T).
zorbs([]) --> [].
zorb(a) --> [1,2].
zorb(b) --> [3].
zorb(c) --> [6,1,2,2].
I can do this:
?- phrase(zorbs(X), [1,2,3,6,1,2,2]).
X = [a, b, c] .
I can also "reverse" this by doing:
phrase(zorbs([a,b,c]), X).
X = [1, 2, 3, 6, 1, 2, 2].
Now, what I want to do is find a list of numbers with length less than 4 (for example) which these elements "parse" into, returning the rest.
So, for example, given [a,b,c], which would normally relate to [1, 2, 3, 6, 1, 2, 2], I want it to relate to [1, 2, 3] (which has length less than 4) and also give the remainder that couldn't be "reversed," so [c]. I don't really know where to start, as it seems there's no way to reason about the number of elements you've already consumed in a DCG.
Here's a sort-of solution:
X in 0..4,
indomain(X),
Q = [_|_],
prefix(Q, [a,b,c]),
length(A, X),
phrase(zorbs(Q), A).
but I think this is very inefficient, because I think it basically iterates up from nothing, and I want to find the solution with the biggest Q.
There is no direct way how to do this in this case. So your approach is essentially what can be done. That is, you are enumerating all possible solutions and (what you have not shown) selecting them accordingly.
Questions about the biggest and the like include some quantification that you cannot express directly in first order logic.
However, sometimes you can use a couple of tricks.
Sometimes, a partial list like [a,b,c|_] may be helpful.
?- Xs = [_,_,_,_|_], phrase(zorbs(Xs),[1,2,3,6,1,2,2]).
false.
So here we have proven that there is no list of length 4 or longer that corresponds to that sequence. That is, we have proven this for infinitely many lists!
And sometimes, using phrase/3 in place of phrase/2 may help. Say, you have a number sequence that doesn't parse, and you want to know how far it can parse:
?- Ys0 = [1,2,3,6,1,2,7], phrase(zorbs(Xs),Ys0,Ys).
Ys0 = [1,2,3,6,1,2,7], Xs = [], Ys = [1,2,3,6,1,2,7]
; Ys0 = [1,2,3,6,1,2,7], Xs = "a", Ys = [3,6,1,2,7]
; Ys0 = [1,2,3,6,1,2,7], Xs = "ab", Ys = [6,1,2,7]
; false.
(This is with the two DCG-rules exchanged)
Can use:
% Like "between", but counts down instead of up
count_down(High, Low, N) :-
integer(High),
integer(Low),
count_down_(High, Low, N).
count_down_(H, L, N) :-
compare(C, H, L),
count_down_comp_(C, H, L, N).
count_down_comp_('=', _H, L, N) :-
% All equal, final
N = L.
% Accept H as the counting-down value
count_down_comp_('>', H, _L, H).
count_down_comp_('>', H, L, N) :-
H0 is H - 1,
% Decrement H towards L, and loop
count_down_(H0, L, N).
... and then start with:
count_down(4, 1, Len), length(Lst, Len), phrase...
Another method is to use freeze to limit a list's length, element-by-element:
max_len_freeze(Lst, MaxLen) :-
compare(C, MaxLen, 0),
max_len_freeze_comp_(C, Lst, MaxLen).
max_len_freeze_comp_('=', [], 0).
max_len_freeze_comp_('>', [_|Lst], MaxLen) :-
succ(MaxLen0, MaxLen),
!,
freeze(Lst, max_len_freeze(Lst, MaxLen0)).
max_len_freeze_comp_('>', [], _).
... and then start with:
max_len_freeze(Lst, 4), phrase...
This will work to find the longest list (maximum length 4) first, since your DCG is greedy (i.e. matching [H|T] before []).

Prolog decimal number to list of numbers

I am new to this page, but hopefully, I'll get the help that I need. I need to code a program that gives a list of numbers from 0-9 from a given bigger number. I don't know how to explain it better, so I add the example:
numbertolist(Number,List).
?- numbertolist(1456,List).
List = [1,4,5,6].
The main thing, that I can't use number_chars/2, number_codes/2 functions, which would give this result easily, I should implement all the functions.
number_codes(123456,X), maplist(plus(48),Y,X).
gives
Y = [1,2,3,4,5,6]
A solution without calling number_codes/2 is straight
forward, using the accumulator programming pattern:
number_digits(N, L) :-
number_digits(N, [], L).
number_digits(0, L, L) :- !.
number_digits(N, L, R) :-
D is N rem 10,
M is N // 10,
number_digits(M, [D|L], R).
The Prolog program gives:
?- number_digits(1454, X).
X = [1, 4, 5, 4].

PROLOG program semantic and exercise

First of all I have a doubt about the semantic of a program , for example :
length([],0).
length([_|L],N):-
length(L,N0),
N is N0 + 1.
The first instruction means the base case , or it has other meanings ?
I have to write a prolog program that, given a number, returns a list of numbers from 0 to the given number.
For example, when the input is 5, the output is [0,1,2,3,4,5].
I'm looking for a solution of this problem but I do not know how to start.
There is a predicate in SWI-Prologs library that does almost what you need to do. It is called numlist/3. You can use it with lower and upper boundary:
?- numlist(1, 5, L).
L = [1, 2, 3, 4, 5].
And here the implementation:
numlist(L, U, Ns) :-
must_be(integer, L),
must_be(integer, U),
L =< U,
numlist_(L, U, Ns).
numlist_(U, U, List) :-
!,
List = [U].
numlist_(L, U, [L|Ns]) :-
L2 is L+1,
numlist_(L2, U, Ns).
You can get rid of the upper half of this completely, and lose one argument (your Lower is just 1).
If you play with this a bit you should be able to figure it out.

Deleting first N prime numbers from a list (Prolog)

Basically I want to remove the first N numbers from a list, the function that checks whether a number is prime or not seems to work well but the program itself doesn't
For example for input [2,4,5,7,6,9,11] and N = 3 I should get [4, 6, 9, 11] but I get only [4, 6, 9].
divisible(X,Y) :-
0 is X mod Y, !.
divisible(X,Y) :-
X > Y+1,
divisible(X, Y+1).
%isPrime function check whether or not the argument is a prime number
isPrime(2) :- true,!.
isPrime(X) :- X < 2,!,false.
isPrime(X) :- not(divisible(X, 2)).
%delFunction (input_list, N, output_list)
delFunction([],_,_).
delFunction(_,0,_).
delFunction([H|T], N, [H|Res]):-
not(isPrime(H)), !,
delFunction(T, N, Res).
delFunction([_|T], N, Res):-
N1 is N-1,
delFunction(T,N1,Res).
delFunction([2,4,5,7,6,9,11],3,X) -> [4,6,9] (which is not the correct answer)
Honestly, I don't know where I went wrong, the implementation idea seems pretty easy and straight forward, so is the code.
Also, when I run it it stops at [4] and I have to keep on clicking next to get me to the end of the execution (thus the result). Any idea how to fix it? I'm thinking maybe I need some cuts but not sure where.
P.S: I'd rather not use built-in functions (if there are any that would help in this scenario)
Fists of all, instead of
delFunction([],_,_).
you should write
delFunction([],_,[]).
because when the input list (the left one) is empty, you have to construct the base for the output list: an empty list; with delFunction([], _, _) you don't unify the output list with the empty list so the result end with an not unified variable.
Second. Instead of
delFunction(_,0,_).
you should write
delFunction(L,0,L).
The problem is the same: when number is zero you can "copy" the input in the output; that is, you can unify they; that is delFunction(L,0,L). With delFunction(_,0,_) you don't unify and the result ends with a not unified variable.
Third. In the is-prime clause
delFunction([_|T], N, Res):-
N1 is N-1,
delFunction(T,N1,Res).
you should check that N is greater than zero
delFunction([_|T], N, Res):-
N > 0,
N1 is N-1,
delFunction(T,N1,Res).
or, if you prefer, you should add a cut (!) in the zero clause
delFunction(L,0,L) :- !.
Just to avoid that Prolog, via backtracking, can give multiple undesired answers.
--- EDIT ---
As Guy Coder, I avoid cuts like a plague; so I propose the following solution to avoid unwanted repetitions.
delFunction([], _, []).
delFunction([H | T], 0, [H | T]).
delFunction([H | T], N, [H | Res]) :-
N > 0,
not(isPrime(H)),
delFunction(T, N, Res).
delFunction([H | T], N, Res):-
N > 0,
isPrime(H),
N1 is N-1,
delFunction(T, N1, Res).

Finding the largest even number in list

The point of this program is supposed to be to find the largest even number inside a list. For example, the query:
? - evenmax([1, 3, 9, 16, 25, -5, 18], X]
X = 18.
The way I thought to do this is to separate the list into two, one with just odd numbers and one with just even numbers. However, after doing that, I legitimately have no idea how to take the even-number list specifically and find the maximum integer in that.
Here is what I currently have:
seperate_list([], [], []).
separate_list([X|Xs], [X|Even], Odd) :-
0 is X mod 2,
separate_list(Xs, Even, Odd).
separate_list([X|Xs], Even, [X|Odd]) :-
1 is X mod 2,
separate_list(Xs, Even, Odd).
find_max([X|Xs], A, Max).
X > A,
find_max(Xs,X,Max).
find_max([X|Xs],A,Max) :-
X =< A,
find_max(Xs,A,Max).
find_max([],A,A).
I am still a newcomer to Prolog, so please bear with me...and I appreciate the help.
You could do it in one go. You can find the first even number in the list, then use this as seed and find the largest even number in the rest of the list.
But if you don't insist on doing it in a single traversal through the list, you can first collect all even numbers, then sort descending and take the first element of the sorted list.
evenmax(List, M) :-
include(even, List, Even),
sort(Even, Sorted),
reverse(Sorted, [M|_]).
even(E) :-
E rem 2 =:= 0.
If you want to see how include/2 is implemented, you can look here. Basically, this is a generalized and optimized version of the separate_list/3 that you have already defined in your question. sort/2 is a built-in, and reverse/2 is a library predicate, implementation is here.
There are many other ways to achieve the same, but for starters this should be good enough. You should ask more specific questions if you want more specific answers, for example:
What if the list has free variables?
What if you want to sort in decreasing order instead of sorting and then reversing?
How to do it in a single go?
and so on.
Sorry but... if you need the maximum (even) value... why don't you simply scan the list, memorizing the maximum (even) value?
The real problem that I see is: wich value return when there aren't even values.
In the following example I've used -1000 as minumum value (in case of no even values)
evenmax([], -1000). % or a adeguate minimum value
evenmax([H | T], EM) :-
K is H mod 2,
K == 0,
evenmax(T, EM0),
EM is max(H, EM0).
evenmax([H | T], EM) :-
K is H mod 2,
K == 1,
evenmax(T, EM).
-- EDIT --
Boris is right: the preceding is a bad solution.
Following his suggestions (thanks!) I've completely rewritten my solution. A little longer but (IMHO) a much better
evenmaxH([], 1, EM, EM).
evenmaxH([H | T], 0, _, EM) :-
0 =:= H mod 2,
evenmaxH(T, 1, H, EM).
evenmaxH([H | T], 1, M0, EM) :-
0 =:= H mod 2,
M1 is max(M0, H),
evenmaxH(T, 1, M1, EM).
evenmaxH([H | T], Found, M, EM) :-
1 =:= H mod 2,
evenmaxH(T, Found, M, EM).
evenmax(L, EM) :-
evenmaxH(L, 0, 0, EM).
I define evenmax like there is no member of list L which is even and is greater than X:
memb([X|_], X).
memb([_|T], X) :- memb(T,X).
even(X) :- R is X mod 2, R == 0.
evenmax(L, X) :- memb(L, X), even(X), not((memb(L, Y), even(Y), Y > X)), !.
There are already a number of good answers, but none that actually answers this part of your question:
I legitimately have no idea how to take the even-number list
specifically and find the maximum integer in that
Given your predicate definitions, it would be simply this:
evenmax(List, EvenMax) :-
separate_list(List, Evens, _Odds),
find_max(Evens, EvenMax).
For this find_max/2 you also need to add a tiny definition:
find_max([X|Xs], Max) :-
find_max(Xs, X, Max).
Finally, you have some typos in your code above: seperate vs. separate, and a . instead of :- in a clause head.

Resources