Prolog: writing a program like Watson in Jeopardy - prolog

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.

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 - Comparing Lists that have the same element on the same index

I've been working on Prolog for a few weeks right now. I am now trying to write a function in it called matching:
Write a predicate called matching with three parameters, all lists.
The third list must contain the index of the positions in which
the first two lists contain the same value.
If I run
matching([10,71,83,9,24,5,2],[8,71,26,9],Positions).
The results are:
?- matching([10,71,83,9,24,5,2],[8,71,26,9],Positions).
Positions = [] ;
Positions = [] ;
Positions = [_2420] ;
Positions = [_2420] ;
Positions = [_2420, _2432];...
The correct answer would be that Positions is bound to [1,3]. I have no idea what is wrong with my code. Any hint is appreciated.
A hint? Each of your matchingHelper clauses contains a mistake!
OK, a little more than a hint:
Base cases
Prolog should be giving you a warning about singleton variables here. ListofIndex is a variable, but it is only used in one place. Essentially this means that there is absolutely no constraint on this, and thus can be anything.
The correct thing would be that if either of the input lists is empty, the output is also empty.
matchingHelper([], _, , []).
matchingHelper(, [], _, []).
Equal case
This one you almost have correct, but the way you deal with ListOfIndex is backwards. You construct a NewListOfIndex based on the predicate arguments, and use that in the recursive call. The problem is that the ListOfIndex is actually the output! So you should instead construct the ListOfIndex based on the output from the recursive call.
matchingHelper([X|Xs], [X|Ys], Index, [Index|ListofIndex]) :-
Index2 is Index + 1,
matchingHelper(Xs, Ys, Index2, ListofIndex).
Unequal case
Just 2 little issues with this one. First is that this clause should only apply if X and Y are different. Just using a different variable name does not enforce this. Because there is a previous clause which handles the equal case, the first result prolog finds would be correct, but it will continue to find other, incorrect solutions because of this.
The second issue is that you don't increment the index. If you ignore the first element, the current index has to be incremented to reflect the current position.
matchingHelper([X|Xs], [Y|Ys], Index, ListofIndex) :-
X \= Y,
Index2 is Index + 1,
matchingHelper(Xs, Ys, Index2, ListofIndex).
Here's a sample run:
?- matching([10,71,83,9,24,5,2],[8,71,26,9],Positions).
Positions = [1, 3]
false

PROLOG extracting words from string and putting them into List

I'm new to Prolog and I can't really think of any ways of dealing with this problem, basically i have a sentence for example:
phrase(det(a),np2(adj(large))).
From the sentence above I want to be able to extract in this case determiner (a) and adjective (large) and put them into a list so it looks like:
newList[a,large].
As you are working with phrase structure trees, which themselves represent grammar rules you might consider using DCGs for your task. First think about what your predicate should describe: a relation between a phrase structure tree and a list that consists of the words of that tree. You could name it pstree_words/2. Consider the minimal example below:
pstree_words(Phrase,List) :-
phrase(Phrase,List).
phrase(det(A),np2(NP)) --> % a phrase is
det(A), % a det followed
np2(NP). % by a np2
det(a) --> % a is a determiner
[a]. % hence in the list
np2(adj(A)) --> % a np2 is
adj(A). % an adj
adj(large) --> % large is an adjective
[large]. % hence in the list
Note that the first goal of pstree_words/2 is not your structure phrase, but the built in predicate phrase/2 for handling DCGs. You can already use this to query for the words in the phrase structure tree:
?- pstree_words(phrase(det(a),np2(adj(large))),L).
L = [a,large]
If you want to add words you just need to add according rules. For example to add the determiner "the" you just add:
det(the) -->
[the].
To add new phrase structures you just add new rules to phrase//2. However, if you try to query pstree_words the other way round, that is, to ask whether or not a sequence of words match a known phrase structure, it does not work. To remedy that you can alter the definition of pstree_words/2:
pstree_words(Phrase,List) :-
is_phrase(Phrase),
phrase(Phrase,List).
is_phrase(phrase(_,_)).
The fact is_phrase/1 simply restricts Phrase to a two-place structure. If you add grammar rules to match e.g. 3-place structures for phrase you also add according facts for is_phrase/1: is_phrase(phrase(_,_,_)). With these alterations the predicate now works in the other direction too:
?- pstree_words(PST,[a,large]).
PST = phrase(det(a),np2(adj(large)))
Other possibly interesting uses: Which phrases with the words [D,large] are there?
?- pstree_words(PST,[D,large]).
D = a,
PST = phrase(det(a),np2(adj(large))) ? ;
D = the,
PST = phrase(det(the),np2(adj(large)))
Which phrases of the given structure are there?
?- pstree_words(phrase(det(D),np2(adj(A))),L).
A = large,
D = a,
L = [a,large] ? ;
A = large,
D = the,
L = [the,large] ? ;

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.

PROLOG -- logic base of entries to LIST of entries

In PROLOG I have a logic base of entries (which are stored in memory) which I have to convert to a list of entries.
example:
| ?- rule(A,B).
A = member(_h209,[_h209|_h212])
B = true;
A = member(_h209,[_h211|_h212])
B = member(_h209,_h212);
TO
[member(_h209,[_h209|_h212]),true,member(_h209,[_h211|_h212]),member(_h209,_h212);]
Can anyone please let me know how can I get it.
something close to your expected result (except the semicolon at end) could be:
rule_list(Rules) :-
findall([A, B], rule(A, B), L),
flatten(L, Rules).
A note on _h209, occurring at first position of member: I'm not sure you know the meaning of such symbols. These are variables, and if you interested in mantaining the identities these express, my suggestion isn't correct. Use bagof in such case.

Resources