Prolog - Counting specific elements in list of lists - prolog

I have a list 'a' in Prolog.
a = [].
I have to insert to 'a' another list 'b'
b = [bottle].
The final result has to be like this:
a = [[bottle]].
The build-in function append/3 seems to only concatenate two lists.
append([item1,item2],[item3,item4],Ans) gives us Ans = [item1,item2,item3,item4] but I need
Ans = [[1,2,3],[4,5,6]].`
Can you please help me with this task, I am completely noob in prolog.

Related

Prolog nth1 anonymous variables

I have a List with Integers and anonymous variables and I try to find the index of a special values. Problem is as soon I'm using nth1/3 to find the indices Prolog assigns values to the anonymous variables and therefore I find way too indices.
Example:
List = [1,\_,1], where I want as result X = 1, X = 3 from nth1(X,List,1), but as stated before I get X = 1, X = 2, X = 3.
There is a somewhat problematic issue hidden in your requirements: They violate an important declarative property called monotonicity. By this we mean that adding constraints can at most make the solution more specific, never more general.
For example, with the solution you posted, we get:
?- list_el_index([_], 1, N).
false.
Now I add a constraint by imposing an additional requirement on the hitherto free anonymous variable:
?- Var = 1, list_el_index([Var], 1, N).
Var = 1,
N = 0 .
I mean: Come on! We have added a constraint, and as a result get more solutions than before? Such a result is unfortunate and prevents us from reasoning in a logical way about this program.
The program also fails us in other respects. For example, let us ask: Which solutions are there at all?
?- list_el_index(Ls, El, I).
nontermination
Ideally, we would like the program to generate solutions in such cases! This generality is one of the foremost attractions of logic programming, and distinguishes it from more low-level paradigms.
One way to solve such issues is to symbolically distinguish the different kinds of elements that appear in your list.
For example, let us use:
u for an unknown value.
i(I) for an integer I.
With this new representation, your solution becomes:
list_el_index([i(I)|_], I, 0).
list_el_index([_|Tail], Element, Index) :-
list_el_index(Tail, Element, Index0),
Index #= Index0+1.
I have also taken the liberty to replace (is)/2 by (#=)/2, to advertise and stick to more general integer arithmetic that lets us more freely reorder the goals, if necessary. Depending on your Prolog implementation, you may have to import a library to benefit from (#=)/2.
With this representation, your initial case becomes:
?- list_el_index([i(1),u,i(1)], 1, Index).
Index = 0 ;
Index = 2 ;
false.
This works as desired!
Importantly, we can use the predicate also more generally, namely to generate possible answers:
?- list_el_index(Ls, El, I).
Ls = [i(El)|_2994],
I = 0 ;
Ls = [_2992, i(El)|_3000],
I = 1 ;
Ls = [_2992, _2998, i(El)|_3006],
I = 2 ;
Ls = [_2992, _2998, _3004, i(El)|_3012],
I = 3 .
Due to the program's monotonicity, we can fairly enumerate solutions by iterative deepening:
?- length(Ls, _), list_el_index(Ls, El, I).
Ls = [i(El)],
I = 0 ;
Ls = [i(El), _4812],
I = 0 ;
Ls = [_4806, i(El)],
I = 1 ;
Ls = [i(El), _4812, _4818],
I = 0 ;
etc.
This has become possible by using a representation that lets us distinguish the cases by pattern matching. Consider using this approach to make your programs usable in all directions, and to make logical reasoning applicable. It is quite easy to apply by using the appropriate wrapper or constant, and greatly increases the generality of your programs.
This works :
- L = [1,_,1], nth1(X, L, Y), ground(Y), Y= 1.
L = [1,_310914,1],
X = Y, Y = 1 ;
L = [1,_310914,1],
X = 3,
Y = 1.
Thanks to lurkers hint, I came up with this solution.
list_el_index([El1|_], El2, 0) :-
El1 == El2.
list_el_index([_|Tail], Element, Index) :-
list_el_index(Tail, Element, Index1),
Index is Index1+1.

Prolog printing all solutions and wanting to get yes/no output

I just started learning Prolog and my task is to write a predicate poklapanje(M,V) which returns yes if all the elements of list M are the first elements of list V, for example poklapanje([1,2],[1,2,3]) should return yes. The first question I have is what is the difference between true and yes, because I am getting true in my solution? Second, when I type poklapanje(X,[1,2,3]) I should get:
X = [];
X = [1];
X = [1,2];
X = [1,2,3];
no
and I get:
X = [];
false
Why? I guess it has something to do with my implementation and printing true/false instead of yes/no.
Here is my code:
poklapanje([],[_|_]).
poklapanje([A|B],[C|D]):- A == C, poklapanje(B,D).
There is no difference between yes and true. It's just difference between Prolog implementations. For example, we get true in SWI-Prolog, and yes in GNU Prolog.
I'm not sure how you posed your query. Here's the output from running your code:
?- poklapanje(X,[1,2,3]).
X = [] ;
X = [1] ;
X = [1, 2] ;
false.
It's missing [1, 2, 3] because poklapanje([],[_|_]). fails for poklapanje([],[]).
I would implement it like this:
poklapanje([], _).
poklapanje([A|B],[A|D]) :- poklapanje(B,D).
Since I cannot add a comment (not enough reputation), i'm putting this here. I'll try to explain why your code doesn't work and why Fabricator's code works.
First problem you have, is
A == C
which is not doing what you wanted to achieve. Instead, you want to unify variables, so use
A = C
or even better, as suggested in the correct answer
poklapanje([A|B],[A|D])
If you do it with A == C, in the second step you would have 1 == C, and this will fail as C is not equal to 1.
Second issue, which is already explained, is
poklapanje([],[_|_]).
which will fail in the last step, where D is an empty list. Empty list doesn't have any members, so it will not unify with [ _ | _ ]. You might be tempted to use [ _ ] to fix this problem, but that would unify only with the list which has one member. That's why you have to use _, which will unify with any list:
poklapanje([], _).
Hope it clears it up for you a bit. :-)

Prolog: writing a program like Watson in Jeopardy

I'm trying make a program that can find the longest word that you can make with a given set of letters. (Kind of like Watson in Jeopardy)
So far I managed to make it so that if you specify the length of the word, it will give you all the words of that length you can make with the letters you gave it.
The program contains facts word/1 for all English words taken into consideration, like so:
word(ant).
word(computer).
% ... (and many more)
First, I made a predicate called word_letters/2 that turns a word into a list of letters, like the atom_chars/2 predicate.
Then, I wrote a cover/2 predicate to see if a list contains all letters of a previous list:
cover([],[]).
cover([],_).
cover([Head1|Tail1],List2) :-
member(Head1,List2),
select(Head1,List2,Newlist),
cover(Tail1,Newlist).
Then I wrote a solution/3 predicate that turns all the words of a certain length into a list of letters, and checks if that list is covered by letters you gave it first:
solution(Letters,Word,Length) :-
word(Word),
word_letters(Word,Letters2),
length(Letters2,Length),
word_letters(Word,Letters2),
cover(Letters2,Letters).
What I'm trying to do now is making it so that you don't have to specify the length of the word. It should just give the longest possible word, and tell you how long it is.
It should work like this:
?- topsolution([g,i,g,c,n,o,a,s,t], Word, Score).
Word = agnostic,
Score = 8
True
It doesn't look that hard, but I just can't seem to make it work.
It would be great if someone could help or maybe point me in the right direction!
The problem you're facing can be decomposed into two:
Determine the maximum length of all words in the word/1 dictionary.
This is a one-time effort that is required whenever the definition of word/1 changes.
Enumerate all admissible scores—starting with the largest one, not with the smallest one.
Using length/2 and append/3 you could write:
?- length(Ref,7), append(_,Part,Ref).
Ref = [_A,_B,_C,_D,_E,_F,_G], Part = [_A,_B,_C,_D,_E,_F,_G]
; Ref = [_A,_B,_C,_D,_E,_F,_G], Part = [_B,_C,_D,_E,_F,_G]
; Ref = [_A,_B,_C,_D,_E,_F,_G], Part = [_C,_D,_E,_F,_G]
; Ref = [_A,_B,_C,_D,_E,_F,_G], Part = [_D,_E,_F,_G]
; Ref = [_A,_B,_C,_D,_E,_F,_G], Part = [_E,_F,_G]
; Ref = [_A,_B,_C,_D,_E,_F,_G], Part = [_F,_G]
; Ref = [_A,_B,_C,_D,_E,_F,_G], Part = [_G]
; Ref = [_A,_B,_C,_D,_E,_F,_G], Part = []
; false.

Creating concatenation predicate in prolog that works with only one input instantiation

Is it possible to create a predicate in Prolog that concatenates two lists and works in any case of these:
concat(X,Y,[1,2,3,4])
concat(X,[2,3,4],[1,2,3,4])
concat([1,2,3],X,[1,2,3,4])
The best I could make so far was this:
concat([],[],[]).
concat([],X,X).
concat(X,[],X).
concat([X|Y],[A|B],[X|Z]) :- add(Y,[A],K) , add(K,B,Z) .
with the following results:
works correctly:
concat([1,2,3],X,[1,2,3,4])
gives correct answer, then enters infinite loop:
concat(X,[2,3,4],[1,2,3,4])
gives some results (edit: all results, I believe), then enters infinite loop:
concat(X,Y,[1,2,3,4])
results given:
?- concat(X,Y,[1,2,3,4]).
X = [],
Y = [1,2,3,4] ? ;
X = [1,2,3,4],
Y = [] ? ;
X = [1],
Y = [2,3,4] ? ;
X = [1,2],
Y = [3,4] ? ;
X = [1,2,3],
Y = [4] ? ;
I'm trying to make this predicate to learn more about prolog.
As stated, you're just redefining append/3. However, as a learning experience you should notice that you can do this in a simpler and more Prolog-y way:
concat([],X,X).
concat([X|Y],A,[X|Z]) :-
concat(Y,A,Z).
As you see, the definitions for empty second list are needless because in the first definition Prolog copies (or more exactly, unifies) second list to the third (or vice versa) even if it is an empty one. You need to handle an empty list only in the first list to stop the recursion. Besides, using pattern matching you don't need extra predicates to move the head items from a list to another.

Categorise List in Prolog

Alright so I am coding a parser for arithmetic equations. I get the input in a list, e.g. "10+20" = [49,48,43,50,48] and then I convert all the digits to there corresponding numbers e.g. [49,48,43,50,48] = [1,0,43,2,0] and from there I want to put integers > 10 back together.
Converting from ascii -> digits I use a maplist and number_codes to convert.
One approach I had was to just traverse the list and if it's 0-9 store it in a variable and then check the next number, 0-9 append it to the other variable and so on until I hit an operator. I can't seem to simply append digits as it were. Here's my current code.
expression(L) :-
maplist(chars, L, Ls).
chars(C, N) :-
(
C >= "0", "9" >= C -> number_codes(N, [C]);
N is C
).
Not sure if there's a simple way to add to my code (as far as I know, maplist only gives back a list of equal length to the list passed in but I could be mistaken).
Any help is appreciated :)
Yes, maplist only 'gives back' a list of equal length. Moreover, maplist applies a predicate only to one element (basically it's context-free). Therefore, it is not possible to do what you want (combine digits between operators to a single number) with maplist and you would have to write the recursion yourself.
However, you can do something way easier than all this converting back and forth:
expression(L, E):-
string_to_atom(L,A),
atom_to_term(A,E,[]).
Which works like this:
2 ?- expression("1+2",E).
E = 1+2.
3 ?- expression("1+2",E), X is E.
E = 1+2, X = 3.
4 ?- expression("1+2",E), X+Y = E.
E = 1+2, X = 1, Y = 2.
5 ?- expression("1+2+3",E), X+Y = E.
E = 1+2+3, X = 1+2, Y = 3.
Naturally, if you want a list with all the numbers involved you will have to do something recursive but this is kinda trivial imho.
If however you still want to do the converting, I suggest checking Definite Clause Grammars; it will simplify the task a lot.
I answered some time ago with an expression parser.
It will show you how to use DCG for practical tasks, and I hope you will appreciate the generality and simplicity of such approach.
Just a library predicate is required from SWI-Prolog, number//1, easily implemented in Sicstus. Let me know if you need more help on that.

Resources