I have defined a predicate find_word/2 that when given a list of letters (with some letters possibly ungrounded), produces possible words that match the pattern given in the list. This is something like a hangman solver.
word('entity', n, 11).
word('physical entity', n, 1).
word('abstraction', n, 0).
% ... and 200,000 more entries ...
% Example: find_word([_,o,u,n,t,r,y], X) -> X = country
find_word(LetterList, Word) :-
word(Word, _, _),
atom_chars(Word, LetterList).
The code above works as intended. The challenge is that I receive hangman problems from outside the Prolog system as a string (e.g. app_e), where the underscores in the string represent the missing letters to be found by the prolog program above. i.e. I need to convert the app_e string into a list that can be fed into find_word/2.
On my first attempt, I used atom_chars\2:
?- atom_chars(app_e, L), find_word(L, Word).
Unfortunately, this does not work as hoped because atom_chars(app_e, L) -> L = [a, p, p, '_', e]. i.e. the '_' isn't a wildcard.
In summary, given a string app_e, how do I transform it into a list that can be fed into find_word\2 to achieve the same effect as find_word([a,p,p,_,e], Word).?
I think atom_chars/2 is working as intended here, you just need a little cleanup step to finish turning your input into the desired form, which I think you can do quite straightforwardly like so:
charvar('_', _).
charvar(C, C) :- C \= '_'.
Usage looks like this:
?- maplist(charvar, [a,p,p,'_',e], X).
X = [a, p, p, _3398, e] .
Don't worry about the fact that this variable is not rendered as an underscore; your own probably wouldn't be either:
?- X=[_].
X = [_3450].
Related
I am trying to write a tiny recursive rewrite system inspired by Aristid Lindenmayers L-System basically to learn Prolog as well as to think about generative concepts in Prolog. I would like to achieve this without DCG. Due to the initial generate. and output predicate with side effects it is not a 100% pure prolog idea. Don´t hesitate to take the concept apart.
My main problem is at the end of the listing. Matching the rule for every element in the original list and creating a new list with the result of each substitution.
[a] the Axiom becomes [a,b] becomes [a,b,a] and so on. Or better as a list of lists
[[a,b],[a]] to keep it more flexible and comprehensible and then flatten it later?
Basic example without constants, which could be added in a similar way. The Axiom is just used one time at the start. The idea is to encode the rule name or symbol to exchange and the symbols it should be exchanged with, as a fact/relation. Start with generate. would repeat it 20 times with a counter.
% The rules
axiom(a, [a]).
rule(a, [a, b]).
rule(b, [a]).
% Starts the program
generate :-
axiom(a, G),
next_generation(20, G).
% repeats it until counter 0.
next_generation(0, _) :- !.
next_generation(N, G) :-
output(G),
linden(G, Next),
succ(N1, N),
next_generation(N1, Next).
% Concatenates the list to one string for the output
output(G) :-
atomic_list_concat(G,'',C),
writeln(C).
% Here I am stuck, the recursive lookup and exchange.
% How do I exchange each element with the according substitution to a new list
linden([],[]). % Empty list returns empty list.
linden([R],Next) :- % List with just one Element, e.g. the axiom
rule(R, Next). % Lookup the rule and List to exchange the current
linden([H|T], Next) :- % If more than one Element is in the original list
rule(H,E), % match the rule for the current Head/ List element
% ????? % concatenate the result with the result of former elements
linden(T, Next). % recursive until the original list is processed.
% Once this is done it returns the nw list to next_generation/2
Yes, you want lists of lists. Each character can then map cleanly to one corresponding expansion list:
linden([], []).
linden([H|T], [E | Next]) :-
rule(H, E),
linden(T, Next).
(This is simpler and shorter than with a DCG for the same thing, BTW.)
For example:
?- linden([a], Expansion).
Expansion = [[a, b]].
?- linden([a, b, a], Expansion).
Expansion = [[a, b], [a], [a, b]].
Then flatten this to a flat list before expanding the next generation.
I have a predicate that takes two arguments in which the first argument can be a compound one and the second argument is always B. I have also defined some new operators like + and &.
pvc(A, B) :- somestuff(A, B).
Here the user may type something like pvc((x+y)&(A+b), B).
As a beginner in Prolog, what I want to do is to convert the compound A to all lowercase and call somestuff with new AN. So it shall be somestuff((x+y)&(a+b), B).
I tried something like pvc(A, B) :- downcase_atom(A,AN),somestuff(AN, B). But it doesn't seem like to be the correct way. I will appreciate any help.
So, you will need to induct on the structure of your thing, and the easiest way to do this is with the univ operator =../2. First handle your base case, which you did:
downcase_compound(A, B) :- atom(A), downcase_atom(A, B).
Now you will take the structure apart and induct on it using univ:
downcase_compound(A, B) :-
compound(A),
A =.. [Functor|Args],
downcase_compound(Functor, DowncaseFunctor),
maplist(downcase_compound, Args, DowncaseArgs),
B =.. [DowncaseFunctor|DowncaseArgs].
The trick here is simply breaking your compound down into bits you can use, and then recursively calling downcase_compound/2 on those bits. See it in action:
?- downcase_compound((x+y,('A'+b)), X).
X = (x+y, a+b)
What I have to do is, write a predicate Multiplication/3, whose first argument is an integer, second argument is a list, and the third argument is the result of multiplying the integer with the list, for example:
?-Multiplication(3,[2,7,4],Result).
should return
Result = [6,21,12].
Here's my code:
Multiplication(X,[],Result).
Multiplication(X,[Head|Tail],Result) :-
Y is X*Head,
append([Result], [Y], L),
append([],L,Result), // HERE
Multiplication(X,Tail,Result).
And I get the following error:
Domain error: 'acyclic_term ' expected, found '#(lists:append([],S_1,S_1),[S_1=[S_1,1]])'
on the second append call.
If anyone knows why I receive the error, how to fix it or another way to solve this, I'm open to ideas.
Your two goals append([Result], [Y], L), append([],L,Result) are exactly the same as:
L = [Result,Y], L = Result.
or even simpler:
L = [L,Y]
which would result either in silent failure or an infinite term. Instead, your Prolog produces an error, so that you can correct your program.
In your original code:
Multiplication(X,[Head|Tail],Result) :-
Y is X*Head,
append([Result], [Y], L),
append([],L,Result), // HERE
Multiplication(X,Tail,Result).
You're getting a "cycle" because you're appending Result to something to get L, then appending something to L to get Result. That's not good. You also have a capitalized predicate name, which is a syntax error. (I assume that, since you ran your code, it wasn't capitalized in the original version.)
You're new proposed solution is overly complicated. Why do you need the 4th argument? Also, your base case for return (which is return(X, [], Result) doesn't make sense, as it has to singleton variables. The use of append/3 is overkill since recursion handles the iteration through the list elements for you.
Starting from the top, you have a common pattern in Prolog where you want to run a query on corresponding elements of two or more lists. A simple recursive solution would look something like this:
multiplication(_, [], []). % Multiplying anything by the empty list is the empty list
multiplication(M, [X|Xs], [XX|XXs]) :-
XX is M * X,
multiplication(M, Xs, XXs).
Another way to implement this kind of pattern in Prolog is with maplist/3. You can first define the query on corresponding elements:
multiply(X, Y, Product) :- Product is X * Y.
Then use maplist/3:
multiplication(M, List, Result) :-
maplist(multiply(M), List, Result).
Maplist will do a call(multiply(M), ...) on each corresponding pair of elements of List and Result.
I edited the code and came up with this:
multiplication(X,[],Result,Result).
multiplication(X,[Head|Tail],List,Result) :-
Y is X*Head,
append(List, [Y], L),
multiplication(X,Tail,L,Result).
return(X,[],Result).
return(X,L,Result) :-
multiplication(X,L,_,Result).
and the query:
return(2,[1,2],Result).
After the first run, it seems to return Result as it should be, but it runs forever.
So I have something like this:
main :-
% Check whether B,C,D is equal to A
... ,
% Relevant code:
(
(B==A -> write('B is the same as A.'));
(C==A -> write('C is the same as A.'));
(D==A -> write('D is the same as A.'));
).
Is there any way that this could be shortened but still print the relevant letter? There could be 100's of letters to test so this current method is not very nice.
Just a quick note in case you weren't aware of this difference: When you call A == B, you're resting whether the value bound to the variable A is equivalent to the value bound to variable B. But when you use write/1 to output
'B is the same as A.', you are just outputting the atomic literal represented by that string of letters. There is no relationship between the character 'A' as part of an atom and the value bound to a variable which is represented by A (no ') in your source code.
So I'm not 100% clear on your intended result, but here are two different solutions that demonstrate the use of the format family of predicates for outputting values and literals:
If you just want to compare the values of two variables, you can use a predicate to perform the comparison and printout the desired result, which can then be used on all members of a list (forall/2 is appropriate here because we are only concerned with output):
report_on_equality(A, B) :-
A == B,
format('~w is the same as ~w.~n', [A, B]).
report_on_equality(A, B) :-
A \== B,
format('~w is not the same as ~w.~n', [A, B]).
example_1 :-
Vals = [1,4,6,1,7],
forall( member(V, Vals),
report_on_equality(V, 1)
).
But there is no reason to output the value of the variables twice in this case, since if they are equivalent, they will of course be the same value. So maybe you actually want to print out uppercase characters that have been previously associated with values. This, of course, requires that you have first made some paring between uppercase characters and some other values. I have chosen to use a simple list of pairs for this purpose:
report_on_labeled_equality(LabelA-ValA, LabelB-ValB) :-
ValA == ValB,
format('~w is the same as ~w.~n', [LabelA, LabelB]).
report_on_labeled_equality(LabelA-ValA, LabelB-ValB) :-
ValA \== ValB,
format('~w is not the same as ~w.~n', [LabelA, LabelB]).
example_2 :-
Vals = ['B'-1, 'C'-3, 'D'-1, 'E'-4],
forall( member(V, Vals),
report_on_labeled_equality(V, 'A'-1)
).
I have the following task:
Write a method that will add two polynoms. I.e 0+2*x^3 and 0+1*x^3+2*x^4 will give 0+3*x^3+2*x^4.
I also wrote the following code:
add_poly(+A1*x^B1+P1,+A2*x^B2+P2,+A3*x^B3+P3):-
(
B1=B2,
B3 = B2,
A3 is A1+A2,
add_poly(P1,P2,P3)
;
B1<B2,
B3=B1,
A3=A1,
add_poly(P1,+A2*x^B2+P2,P3)
;
B1>B2,
B3=B2,
A3=A2,
add_poly(+A1*x^B1+P1,P2,P3)
).
add_poly(X+P1,Y+P2,Z+P3):-
Z is X+Y,
add_poly(P1,P2,P3).
My problem is that I don't know how to stop. I would like to stop when one the arguments is null and than to append the second argument to the third one. But how can I check that they are null?
Thanks.
Several remarks:
Try to avoid disjunctions (;)/2 in the beginning. They need special indentation to be readable. And they make reading a single rule more complex — think of all the extra (=)/2 goals you have to write and keep track of.
Then, I am not sure what you can assume about your polynomials. Can you assume they are written in canonical form?
And for your program: Consider the head of your first rule:
add_poly(+A1*x^B1+P1,+A2*x^B2+P2,+A3*x^B3+P3):-
I will generalize away some of the arguments:
add_poly(+A1*x^B1+P1,_,_):-
and some of the subterms:
add_poly(+_+_,_,_):-
This corresponds to:
add_poly(+(+(_),_),_,_) :-
Not sure you like this.
So this rule applies only to terms starting with a prefix + followed by an infix +. At least your sample data did not contain a prefix +.
Also, please remark that the +-operator is left associative. That means that 1+2+3+4 associates to the left:
?- write_canonical(1+2+3+4).
+(+(+(1,2),3),4)
So if you have a term 0+3*x^3+2*x^4 the first thing you "see" is _+2*x^4. The terms on the left are nested deeper.
For your actual question (how to stop) - you will have to test explicitly that the leftmost subterm is an integer, use integer/1 - or maybe a term (*)/2 (that depends on your assumptions).
I assume that polynomials you are speaking of are in 1 variable and with integer exponents.
Here a procedure working on normal polynomial form: a polynomial can be represented as a list (a sum) of factors, where the (integer) exponent is implicitly represented by the position.
:- [library(clpfd)].
add_poly(P1, P2, Sum) :-
normalize(P1, N1),
normalize(P2, N2),
append(N1, N2, Nt),
aggregate_all(max(L), (member(M, Nt), length(M, L)), LMax),
maplist(rpad(LMax), Nt, Nn),
clpfd:transpose(Nn, Tn),
maplist(sumlist, Tn, NSum),
denormalize(NSum, Sum).
rpad(LMax, List, ListN) :-
length(List, L),
D is LMax - L,
zeros(D, Z),
append(List, Z, ListN).
% the hardest part is of course normalization: here a draft
normalize(Ts + T, [N|Ns]) :-
normalize_fact(T, N),
normalize(Ts, Ns).
normalize(T, [N]) :-
normalize_fact(T, N).
% build a list with 0s left before position E
normalize_fact(T, Normal) :-
fact_exp(T, F, E),
zeros(E, Zeros),
nth0(E, Normal, F, Zeros).
zeros(E, Zeros) :-
length(Zeros, E),
maplist(copy_term(0), Zeros).
fact_exp(F * x ^ E, F, E).
fact_exp(x ^ E, 1, E).
fact_exp(F * x, F, 1).
fact_exp(F, F, 0).
% TBD...
denormalize(NSum, NSum).
test:
?- add_poly(0+2*x^3, 0+1*x^3+2*x^4, P).
P = [0, 0, 0, 3, 2]
the answer is still in normal form, denormalize/2 should be written...