How to ask for user choice in Prolog? - menu

I've just started learning Prolog. I am practicing from a fruit sample. but I could not create a structure that allows users to select by number. The examples I look at on the internet are not effective on the fruit sample.
when I run the following code on SWISH-Prolog, I have to write the values ​​in the list one by one. how can I select "1,2,3,4" instead of red, orange, yellow, green, purple, peach?
error code block:
menuask(Attr, Val, List) :-
write('What is the value for '), write(Attr), write('? '), nl,
write (1. red), nl,
write (2. orange), nl,
read(Ans),
check_val(Ans, Attr, Val, List),
asserta(known(yes, Attr, Ans)),
Ans == Val.
in the "menuask" gives an error. I tried it.
Prolog All Codes:
:- dynamic(known/3).
:- discontiguous menuask/3.
:- discontiguous ask/2.
%
% % Data: fruit(X) :- attributes(Y)
fruit(banana) :- colour(yellow), shape(crescent).
fruit(apple) :- (colour(green); colour(red)), shape(sphere), stem(yes).
fruit(lemon) :- colour(yellow), (shape(sphere);shape('tapered sphere')), acidic(yes).
fruit(lime) :- colour(green), shape(sphere), acidic(yes).
fruit(pear) :- colour(green), shape('tapered sphere').
fruit(plum) :- colour(purple), shape(sphere), stone(yes).
fruit(grape) :- (colour(purple);colour(green)), shape(sphere).
fruit(orange) :- colour(orange), shape(sphere).
fruit(satsuma) :- colour(orange), shape('flat sphere').
fruit(peach) :- colour(peach).
fruit(rhubarb) :- (colour(red); colour(green)), shape(stick).
fruit(cherry) :- colour(red), shape(sphere), stem(yes), stone(yes).
% Expert recogniser
% Asks
colour(X) :- menuask(colour, X, [red, orange, yellow, green, purple, peach]).
shape(X) :- menuask(shape, X, [sphere, crescent, 'tapered sphere', 'flat sphere', stick]).
acidic(X) :- ask(acidic, X).
stem(X) :- ask(stem, X).
stone(X) :- ask(stone, X).
% Remember what I've been told is correct
ask(Attr, Val) :- known(yes, Attr, Val), !.
menuask(Attr, Val, _) :- known(yes, Attr, Val), !.
% % Remember what I've been told is wrong
ask(Attr, Val) :- known(_, Attr, Val), !, fail.
menuask(Attr, Val, _) :- known(_, Attr, Val), !, fail.
% Remember when I've been told an attribute has a different value
ask(Attr, Val) :- known(yes, Attr, V), V \== Val, !, fail.
menuask(Attr, Val, _) :- known(yes, Attr, V), V \== Val, !, fail.
% % I don't know this, better ask!
ask(Attr, Val) :- write(Attr:Val), write('? '), read(Ans), asserta(known(Ans, Attr, Val)), Ans == yes.
menuask(Attr, Val, List) :-
write('What is the value for '), write(Attr), write('? '), nl,
write(List), nl,
read(Ans),
check_val(Ans, Attr, Val, List),
asserta(known(yes, Attr, Ans)),
Ans == Val.
check_val(Ans, _, _, List) :- member(Ans, List), !.
check_val(Ans, Attr, Val, List) :-
write(Ans), write(' is not a known answer, please try again.'), nl,
menuask(Attr, Val, List).
go :- fruit(Fruit), write('The fruit is '), write(Fruit), nl.

I'm not totally clear on the focus of the question, but perhaps this will help. Here's a brief example of how to get a name corresponding to a number input:
fruit(1, apple).
fruit(2, pear).
fruit(3, orange).
read_fruit(FruitName) :-
repeat,
write('Please select a fruit:'), nl,
write_fruit_list,
read(FruitNumber),
( fruit(FruitNumber, FruitName)
-> write('You selected: '), write(FruitName), nl, !
; write('Not a valid choice, try again...'), nl, fail
).
write_fruit_list :-
fruit(N, Name),
write(N), write('. '), write(Name), nl,
fail.
write_fruit_list.
Here's what it looks like when you use it:
2 ?- read_fruit(F).
Please select a fruit:
1. apple
2. pear
3. orange
|: 4.
Not a valid choice, try again...
Please select a fruit:
1. apple
2. pear
3. orange
|: 3.
You selected: orange
F = orange.
3 ?-
You can remove the cut if you want it to continuously ask for fruit inputs.

Related

replacing '==' with 'in' operator in if conditions

When I started to traverse a code of my friend, I came across two declarations of if clause.
one is declared as follows:
(CASE A)
if x not in ('a', 'b'):
pass
another is declared like this:
(CASE B)
if x != 'a' or x != 'b':
pass
(CASE C)
if x != 'a' and x != 'b':
pass
I've simplified the values as 'a' and 'b' but the actual values are complicated and pretty long. When I run them separately, I got the same output.
Which one does CASE A match with? CASE B or CASE C.
Also which form of writing is correct? using in or using equality operator.
They not the same, if you start from Case A, hopefully it is easy to see.
Consider case A.
x not in ('a', 'b')
This literally means, x is not equal to 'a' and x is not equal to 'b'. Or written as code.
x != 'a' and x != 'b'
That happens to be case C.
Case B on the other hand is exactly the same as C but it has an 'or' instead of an 'and'.
'or' does not perform the same operation as 'and', therefore case C is different.
x = 'a'
print("A", x not in ('a', 'b') )
print("B", x != 'a' or x != 'b')
print("C", x != 'a' and x != 'b')
In or statement you are saying that if you found any of the operands true then no need to check the other operands because the result will be true anyway.
In CASE B if x was (not 'a') then it's true and it'll not check if x is equals to 'b'.
You can simply test the cases by printing x as follows:
>>> x='b'
>>> if x not in ('a', 'b'): #CASE A (nothing printed when x='b')
... print(x)
...
>>> if x != 'a' or x!='b': #CASE B
... print(x)
...
b # The condition is true so x's value printed
>>> if x != 'a' and x!='b': #CASE C (nothing printed when x='b')
... print(x)
...
>>>
Here you can find that A and C have the same output (which is nothing).
Definitely, CASE C.
x not in ('a', 'b') means that x has not been appeared in given elements.
CASE B can be converted into correct form with:
if not (x == 'a' or x == 'b'):
pass

I am confuse about this code can someone explain

Changing Duplicate characters in a string to ) and non duplicate to (.
I have tried 2 for loops but it doesn't work. I am beginner in coding therefore I cant understand this complex code can someone explain.
def duplicate_encode(word):
return (lambda w: ''.join(('(', ')')[c in w[:i] + w[i+1:]] for i, c in enumerate(w)))(word.lower())
print(duplicate_encode("rEcede"))
Input: "Mercedes Bench"
Output: ()())()((()()(
As said in a comment, I think this is bad coding practice and should be avoided. But it can serve as an example of code reading. So I'll give it a try here. (First you should read about lambda if you're not familiar with it.)
First, look at the matching parentheses and try to find the "deepest" parts:
The top one is: lambda w: ''.join(('(', ')')[c in w[:i] + w[i+1:]] for i, c in enumerate(w))) applied to word.lower().
Then we have ('(', ')')[c in w[:i] + w[i+1:]] for i, c in enumerate(w)) in place of three dots inside ''.join(...).
enumerate(w), where w is a string, will produce an enumerate object that can be iterated to get tuples of form (i,c), where i is the index of the letter c. Try running for x in enumerate(w): print(x) for different strings w in order to get a feel for it.
The ('(', ')')[c in w[:i] + w[i+1:]] for i, c in enumerate(w)) will then produce a generator object by iterating through the tuples of letters of w and the respective indices that will consist of only ')' and '(' that will be then concatenated by ''.join(...) into the final output string. Let's break it down further.
[c in w[:i] + w[i+1:]] will always evaluate to either [True] or [False] (see 6 as to why). Now, ('(', ')')[False] will return '(' and ('(', ')')[True] will return ')' (something I learned right now by typing it out to see what happens).
For any letter in w there will be a tuple in the generator object (see point 4), (i, c). The [c in w[:i] + w[i+1:]] will first take two substrings of w. The first one will include all the letters up to the position i (where the current letter is located) and the second will include all the letters after the current letter. These two substrings are then concatenated. Then c in part will just check if the current letter is in the resulting string, effectively checking if the letter c appears at some other part of the string as well. For example for a w = 'aba' and second tuple from enumerate('aba'), that is (1, 'b'), w[:i] will be equal to 'aba'[:1] which is 'a' and w[i+1:] will be equal to 'aba'[:1] which is equal to 'a', concatenated we get a string 'aa' and thus [c in w[:i] + w[i+1:]] which in this case is equal to ['b' in 'aa'] will evaluate to [False], hence resulting in '('.
Effectively the lambda part is just a function that for each letter at a given position, checks if the same letter is present in a modified string with the letter removed from that position. It is then applied to an argument word.lower() which just insures that the caps are ignored (e.g., 'A' and 'a' are counted as the same letter).
This code replicates exactly what the lambda function does. By separating the logic into distinct statements it is easier to follow the logic. Remove the comments from the print statements to see the whole process in detail.
def simple_duplicate_encode(word):
output = ""
for i, c in enumerate(word):
# print(i,c)
i1 = word[:i]
i2 = word[i+1:]
# print(":{} = {}".format(i, word[:i]))
# print("{}: = {}".format(i+1, word[i+1:]))
is_duplicated = c in i1 + i2 # Check to see if the character c is in the rest of the string
# print("Is duplicated:{}".format(is_duplicated))
character = ('(',')')[is_duplicated] # If is_duplicated = True the value is 1, else 0
# print(character)
output += character
return output

Most efficient way of translating OID's in varBinds to MIB's

After my SNMP transaction is completed and results are stored in varBinds, I'd like to assign the MIB and the value to their own variables for further processing. When I try:
for x in varBinds
print x
the OID is translated, however, I need the mib and the value to be assigned to individual variables when I try:
for oid, val in varBinds
print oid, val
the OID is NOT translated. I have not figured out how to use .loadMibs, so I created a function to translate the OID that I invoke on oid:
T = oid2mib(oid)
def oid2mib(oid_str):
oid_tuple = tuple(oid_str)
mib_builder = builder.MibBuilder()
compiler.addMibCompiler(mib_builder)
mib_builder.loadModules('SNMPv2-MIB')
mib_view = view.MibViewController(mib_builder)
a, b, c = mib_view.getNodeName(oid_tuple)
return b[-1] + '.' + '.'.join(map(str, c))
print('Mib:%s Value:%s' % (T, val))
This works and it translates my OID to MIB, but I am wondering if this is the most efficient way of achieving my desired result? Perhaps .loadMibs might be more efficient?
UPDATE
I Just tried the following,
for x in varBinds
a, b = str(x).split('=')
print(a.rstrip(), b.rstrip(), sep=' => ')
What are the pros and cons of this approach?
Since you get your var-bindings translated in the first case, I suspect you have proper MIB loaded already.
So try this:
for oid, val in varBinds
a, b = str(oid), str(val)
print(a, b, sep=' => ')
You will need to call loadMibs() if you happen to run into the OID for which the MIB is not loaded.

Reversible predicates and Strings in SWI-Prolog

append/3 is a very powerful predicate. Suppose I want a predicate that works the same way but for SWI-Prolog's strings.
The easiest approach I see is to transform those strings into lists with string_codes/2, then apply append/3, then use string_codes/2 back. The big problem with this approach is that string_codes/2 does not work if both variables are not unified.
Here is an extremely ugly solution I came up with, which checks which strings are unified to apply string_codes/2 when needed:
append_strings(S1, S2, S3) :-
nonvar(S1),
nonvar(S2),!,
string_codes(S1, A),
string_codes(S2, B),
append(A,B,C),
string_codes(S3, C).
append_strings(S1, S2, S3) :-
nonvar(S1),
nonvar(S3),!,
string_codes(S1, A),
string_codes(S3, C),
append(A,B,C),
string_codes(S2, B).
append_strings(S1, S2, S3) :-
nonvar(S2),
nonvar(S3),!,
string_codes(S2, B),
string_codes(S3, C),
append(A,B,C),
string_codes(S1, A).
append_strings(S1, S2, S3) :-
nonvar(S3),
string_codes(S3, C),
append(A,B,C),
string_codes(S1, A),
string_codes(S2, B).
This yields the correct results for the following cases:
?- append_strings("test","auie","testauie").
true.
?- append_strings("test",A,"testauie").
A = "auie".
?- append_strings(A,"auie","testauie").
A = "test" ;
false.
?- append_strings(A,B,"testauie").
A = "",
B = "testauie" ;
A = "t",
B = "estauie" ;
A = "te",
B = "stauie" ;
A = "tes",
B = "tauie" ;
A = "test",
B = "auie" ;
A = "testa",
B = "uie" ;
A = "testau",
B = "ie" ;
A = "testaui",
B = "e" ;
A = "testauie",
B = "" ;
false.
Is there really no way to make things simpler than this? Suppose I want to make a whole bunch of predicates that work with strings just like they would with lists: I obviously don't want to have to write what I did for append/3 for all of them. But I also don't want to work with code strings because then I have no way of knowing whether I am manipulating a normal list or really a string.
Since the predicate is working on lists, it seems tempting to me to use DCGs. First let's observe that strings in Prolog are really lists of character codes:
?- X="test".
X = [116,101,115,116]
Of course this is not very readable, so let's see the characters themselves intead of their codes:
?- set_prolog_flag(double_quotes,chars).
yes
?- X="test".
X = [t,e,s,t]
That's better. Thinking about the relation the predicate should describe, I opt for a descriptive name like list_list_appended/3. This predicate has one goal: a dcg-rule, let's call it list_list//2, that uses another dcg, let's call it list//2, to actually write the lists:
list_list_appended(L1,L2,L3) :-
phrase(list_list(L1,L2),L3). % L3 is L1+L2
list([]) --> % if the list is empty ...
[]. % ... there's nothing in the list
list([X|Xs]) --> % if there's a head element ...
[X], % ... it's in the list
list(Xs). % the tail is also a list
list_list(L1,L2) --> % the list consists of ...
list(L1), % ... L1 followed by ...
list(L2). % L2
Your example queries:
?- list_list_appended("test","auie","testauie").
yes
?- list_list_appended(L1,"auie","testauie").
L1 = [t,e,s,t] ? ;
no
?- list_list_appended("test",L2,"testauie").
L2 = [a,u,i,e] ? ;
no
?- list_list_appended("test","auie",L3).
L3 = [t,e,s,t,a,u,i,e]
?- list_list_appended(L1,L2,"testauie").
L1 = [],
L2 = [t,e,s,t,a,u,i,e] ? ;
L1 = [t],
L2 = [e,s,t,a,u,i,e] ? ;
L1 = [t,e],
L2 = [s,t,a,u,i,e] ? ;
L1 = [t,e,s],
L2 = [t,a,u,i,e] ? ;
L1 = [t,e,s,t],
L2 = [a,u,i,e] ? ;
L1 = [t,e,s,t,a],
L2 = [u,i,e] ? ;
L1 = [t,e,s,t,a,u],
L2 = [i,e] ? ;
L1 = [t,e,s,t,a,u,i],
L2 = [e] ? ;
L1 = [t,e,s,t,a,u,i,e],
L2 = [] ? ;
no
As a SWI user you could also use this library in combination with set_prolog_flag(double_quotes,chars). to get the output in desired form. Refer to this answer for details.
Just use string_concat/3. Like ISO atom_concat/3, it can be used in many modes, including (-,-,+).
This is a more compact definition:
append_strings(S1, S2, S3):-
append_strings1(S1, L1, [1]-[], N1),
append_strings1(S2, L2, [1|N1]-N1, N2),
append_strings1(S3, L3, [1,1|N2]-N2, N3),
(N3\=[_,_|_] ->instantiation_error(append_strings/3); true),
append(L1, L2, L3),
(ground(S1)->true;string_codes(S1, L1)),
(ground(S2)->true;string_codes(S2, L2)),
(ground(S3)->true;string_codes(S3, L3)).
append_strings1(S, L, G-NG, N):-
(ground(S) -> (string_codes(S, L), N=G) ; N=NG).
It checks whether each argument is ground and tries to convert to codes, then checks if either the third argument is ground or the other two are, and throws an instantiation error if conditions are not met.
After the append it converts back to string arguments which where not ground.
there has been a similar question some time ago, I will show my proposal, revised
:- meta_predicate when_(0).
when_(P) :-
strip_module(P,_,Q), Q =.. [_|As],
or_list(As, Exp), % hurry debugging :-) display(Exp),
when(Exp, P).
or_list([A], ground(A)) :- !.
or_list([A|As], (ground(A);Exp)) :- or_list(As, Exp).
append_strings(S1, S2, S3) :-
maplist(when_, [string_codes(S1, A), string_codes(S2, B), append(A,B,C), string_codes(S3, C)]).
If you are interested, I can add an operator to hide the syntax details, to get something like
append_strings(S1, S2, S3) -:-
string_codes(S1, A), string_codes(S2, B), append(A,B,C), string_codes(S3, C).

Constraint programming boolean solver

Huey, Dewey and Louie are being questioned by their uncle. These are the statements they make:
• Huey: “Dewey and Louie had equal share in it; if one is guilty, so is the other.”
• Dewey: “If Huey is guilty, then so am I.”
• Louie: “Dewey and I are not both guilty.”
Their uncle, knowing that they are scouts realizes that they cannot tell a lie.
My solution.
var bool :D; var bool :L; var bool :H;
constraint D <->L;
constraint H -> D;
constraint D!=L;
solve satisfy;
output[show(D), "\n", show(L),"\n", show(H)];
Minizinc can't solve it.
Here's my (old) version of this problem: http://www.hakank.org/minizinc/huey_dewey_louie.mzn
var bool: huey;
var bool: dewey;
var bool: louie;
constraint
% Huey: Dewey and Louie has equal share in it; if one is quitly, so is the other.
(dewey <-> louie)
% Dewey: If Huey is guilty, then so am I.
/\
(huey -> dewey)
% Louie: Dewey and I are not both quilty.
/\
(not (dewey /\ louie))
;
For this kind of problems I prefer to use Boolean Satisfiability (SAT) directly. Your problem can obviously be formulated as a propositional logic formula as follows (using the DIMACS format) :
Atom 1 : Dewey is guilty (i.e. will be associated to the literals -1 and 1 in the CNF)
Atom 2 : Louie is guilty (i.e. will be associated to the literals -2 and 2 in the CNF)
Atom 3 : Huey is guilty (i.e. will be associated to the literals -3 and 3 in the CNF)
The CNF file is then :
p cnf 4 3
-1 2 0
-2 1 0
-3 1 0
-1 -2 0
And here the solution using an 'online' SAT Solver : http://boolsat.com/show/5320e18a0148a30002000002
Yet another solution, using CLP(B) (constraint logic programming over Boolean variables) with SICStus Prolog or SWI:
:- use_module(library(clpb)).
guilty(H, D, L) :-
sat(D =:= L), % Huey
sat(H =< D), % Dewey
sat(~(D*L)). % Louie
Example query and its result:
?- guilty(H, D, L).
D = H, H = L, L = 0.
Another option is to ask WolframAlpha:
not (L xor D) and (H implies D) and not (L and D)
As suggested by Hakan, the following equivalent expression is also possible:
(L equivalent D) and (H implies D) and not (L and D)
Result is a truth table which has only (!D !H !L) as solution.

Resources