Prolog: Pass User-Input as Parameters - io

I am new to Prolog and therefore need help with the following task.
I have the programm:
do(save) :- save_bal(bad).
do(act) :- save_bal(good), inc(good).
do(comb) :- save_bal(good), inc(bad).
save_bal(good) :- savMoney(X), depPeople(Y), Min is Y * 1000, X >= Min.
save_bal(bad) :- not(save_bal(good)).
inc(good) :- earn(Z), depPeople(Y), MinE is 3000 + Y * 400, Z >= MinE.
inc(bad) :- not(inc(good)).
savMoney(30000).
earn(60000).
depPeople(4).
My task is to rewrite this programm, so the numbers 30000, 60000 and 4 is set by a user input. How can I do this?
I tried:
:- read(A), savMoney(A).
:- read(B), earn(B).
:- read(C), depPeople(C).
But that won't work.
Can someone point me in the right direction?
Thanks in advance!

Prolog is an homoiconic language, then the first step you should take is to declare which predicate are data, and which are (just to say) logic constraints on the data.
Then, add near top of file (just a stylistic hint) the declarations
:- dynamic(savMoney/1).
:- dynamic(earn/1).
:- dynamic(depPeople/1).
then you can add a service predicate, say user_update_store/1, like
user_update_store(Entry) :-
AccessValueCurr =.. [Entry, ValueCurr],
(retract(AccessValueCurr) -> true ; ValueCurr = 0),
format('enter value for ~s (current is ~w):', [Entry, ValueCurr]),
read(NewValue),
% validate it's a number etc...
StoreNewValue =.. [Entry, NewValue],
assertz(StoreNewValue).
now you can start your user interface:
?- maplist(user_udpdate_store, [savMoney,earn,depPeople]).
this code should work for every (ISO compliant) Prolog. Note: I didn't tested it...
HTH

CapelliC provided an excellent (better) answer while I was busy typing away at this monstrosity. In fact, I didn't end up addressing the question in your title, because you were passing parameters just fine. Instead I wrote about assertz/1 and retract/1. However, I taught myself a fair amount while composing it and you might also find it informative.
In your example code, we have 3 facts declared with the predicates savMoney/1, earn/1, depPeople/1'. We then have a number of rules that determine values based on these facts. A rule is of the form :- ., and which I sometimes read to myself as "<head> is true if <body> is true". We can think of a fact as a rule of the form :- true, e.g.,savMoney(30000) :- true.`, which we might read as "30000 is savMoney if true is true", and true is true or we're all screwed. (BTW, is 'savMoney' short for saved money?)
A directive is of the form :- <body>.. It is like a rule that must be tested in order for the program (or world) to be true (this is more evocative than accurate, because, as you've seen, when a directive fails the whole program-world is not false, we just get a warning). When we consult a prolog file, we add new rules and facts to our program-world, and these can even be impossible nonsense statements like a :- \+ a. "a is true if not-a is true"1. That contradiction will cause cause a stack overflow if you query ?- a., but the program will load just fine. However, directives have to be evaluated and settled while the program loads in the order they are encountered:
This program will throw a stack overflow error when the interpreter consults it.
a :- \+ a.
:- a.
This program will throw an undefined procedure error, because it is being directed to prove a before a has been entered into the database.
:- a.
a :- \+ a.
When we have a directive like :- read(A), savMoney(A)., it's not saying "read the value of user input into A and then set saveMoney to A". Instead, it's saying something more like, "if this program is loaded, then A is a value read in from user input and A is savMoney." Suppose you run the program and enter 100 at the first prompt (the plain prompt is |). What happens?
prolog unifies the variable A with 100.
prolog tries to prove savMoney(100).
it replies Warning: Goal (directive) failed: user:(read(_G2072),savMoney(_G2072)).
This is because, while savMoney(30000) is true, savMoney(100) is not. A directive does not assert the contents of its body, it only tells prolog to prove those contents.
What you are trying to do is allow the user to assert a previously unknown fact into the database. As indicated by mbratch, this requires using the predicate assertz/12. However, predicted that be changed during run-time are differentiated from standard predicates.
If you try to define a reestablished predicate in a program, you'll get an error. E.g., consult a file consisting of the following declaration:
length(2, y).
You'll receive an error:
ERROR: /Users/aporiac/myprolog/swi/studies/test.pl:18:
No permission to modify static procedure `length/2'
Defined at /opt/local/lib/swipl-6.2.6/boot/init.pl:2708
This tells us that 'length/2' is static and that it is already defined in init.pl file at line 2708.
The same happens if you try to assert a static predicate with assertz/1. You can try this by querying assertz(savMoney(100)) in swipl. In order to add new facts or rules about a predicate, we have to declare the predicate to be dynamic.
This is accomplished with dynamic/1. To assure that prolog knows which of our predicates are to be counted as dynamic, we give it a directive like so3:
:- dynamic savMoney/1.
If you've added that to your file (before you define the predicate), you can then query ?- assertz(savMoney(100)). to add the new fact to the database. Now, if you query ?- savMoney(X), you'll get
X = 30000;
X = 100.
There are now two possible values for X, because we've added another fact to the database.
Of course, in your case, you don't want to keep adding values to savMoney/1, you want to be able to update and replace the value.
That calls for retract/1 (If you think there's a chance that more than one occurrence the asserted predicate could get added at some point, then you can use retractall/1 to clear all instances). Now we can write a rule like the following:
set_saved(Amount) :-
retract( savMoney(_) ),
assertz( savMoney(Amount) ).
set_saved(Amount) is true if savMoney(_) can be retracted and removed from the database and the new fact savMoney(Amount) can be asserted.
I've just seen that CapelliC has provided a simple input interface, and a much more concise solution to the problem, but here's my version of your example program in case it might be informative. (I didn't actually get around to adding the prompt and input, but querying, e.g., ?- set_saved(100), does what you'd expect).
:- dynamic [ savMoney/1,
earn/1,
depPeople/1 ].
do(save) :- save_bal(bad).
do(act) :- save_bal(good), inc(good).
do(comb) :- save_bal(good), inc(bad).
save_bal(good) :- savMoney(X), depPeople(Y), Min is Y * 1000, X >= Min.
save_bal(bad) :- not(save_bal(good)).
inc(good) :- earn(Z), depPeople(Y), MinE is 3000 + Y * 400, Z >= MinE.
inc(bad) :- not(inc(good)).
savMoney(30000).
earn(60000).
depPeople(4).
set_saved(Amount) :-
retract( savMoney(_) ),
assertz( savMoney(Amount) ).
set_earned(Amount) :-
retract( earn(_) ),
assertz( earn(Amount) ).
set_people_in_department(Number) :-
retract( depPeople(_) ),
assertz( depPeople(Number) ).
report([Saved, Earned, People]) :-
Saved = savMoney(_) , Saved,
Earned = earn(_) , Earned,
People = depPeople(_), People.
\+/1 is the standard negation operator in swi-prolog and not/1 is depreciated.
assert/1 is equivalent to, and depreciated in favor of, assertz/1. asserta/1 asserts the fact or clause as the first instance of the predicate at hand, while assertz/1 asserts it as the last. (Cf. the manual section on the Database).
Of course, this goes against the interpretation of the directive I suggested before. My interpretation fits when you're using 'normal' predicates in a directive. But, most often, we see directives used for special predicates like in module declarations (:- module(name, [<list of exported predicates>]) or module imports (:- use_module([<list of modules>])).

Related

Freemarker: How to check for ?api-able type (v 2.3.26)

In Freemarker, I have a Map<Map<...>> in the model.
Due to FM glitch, querying for 2nd level Map needs ?api. However, that escapes the normal value existence checks and complicates things.
This is what I have:
<#if sortedStatsMap[rowTag.name]?? && sortedStatsMap[rowTag.name]?is_hash>
${mapToJson(sortedStatsMap[rowTag.name]?api.get(boxTag.name))!}
</#if>
This ends up with:
APINotSupportedTemplateException: The value doesn't support ?api. See requirements in the FreeMarker Manual.
(FTL type: sequence+extended_hash+string (wrapper: f.c.DefaultToExpression$EmptyStringAndSequence),
TemplateModel class: f.c.DefaultToExpression$EmptyStringAndSequence,
ObjectWapper: freemarker.template.DefaultObjectWrapper#1074040321(2.3.26, useAdaptersForContainers=true, forceLegacyNonListCollections=true, iterableSupport=trueexposureLevel=1, exposeFields=false, treatDefaultMethodsAsBeanMembers=true, sharedClassIntrospCache=#1896185155, ...))
The blamed expression:
==> sortedStatsMap[rowTag.name]! [in template "reports/templates/techReport-boxes.ftl" at line 152, column 84]
If I try
sortedStatsMap[rowTag.name]!?is_hash
then this also fails because if missing, it gives me empty_string_and_sequence and ?is_hash can't be applied, reportedly. (Says that in an error.)
What's the proper logic to check whether I can use ?api.get(key)? Or the right way to use ! to handle missing values or a missing key?
You can check if a value supports ?api with ?has_api. Though maybe you don't need that; the example and the problems related to it should be clarified (see my comments).

Remove single quotes/quotation marks in Prolog

I have an extern API sending info to my Prolog application and I found a problem creating my facts.
When the information received is extensive, Prolog automatically adds ' (single quotes) to that info.
Example: with the data received, the fact I create is:
object(ObjectID,ObjectName,'[(1,09:00,12:00),(2,10:00,12:00)]',anotherID)
The fact I would like to create is
object(ObjectID,ObjectName,[(1,09:00,12:00),(2,10:00,12:00)] ,anotherID)
without the ' before the list.
Does anyone know how to solve this problem? With a predicate that receives '[(1,09:00,12:00),(2,10:00,12:00)]' and returns [(1,09:00,12:00),(2,10:00,12:00)]?
What you see is an atom, and you want to convert it to a term I think.
If you use swi-prolog, you can use the builtin term_to_atom/2:
True if Atom describes a term that unifies with Term. When Atom is instantiated, Atom is parsed and the result unified with Term.
Example:
?- term_to_atom(X,'[(1,09:00,12:00),(2,10:00,12:00)]').
X = [ (1, 9:0, 12:0), (2, 10:0, 12:0)].
So at the right hand side, you enter the atom, at the left side the "equivalent" term. Mind however that for instance 00 is interpreted as a number and thus is equal to 0, this can be unintended behavior.
You can thus translate the predicate as:
translate(object(A,B,C,D),object(A,B,CT,D)) :-
term_to_atom(CT,C).
Since you do not fully specify how you get this data, it is unknown to me how you will convert it. But the above way will probably be of some help.

prolog recursive searching with contraints

I have a house with rooms that are defined with connections for when you can go from one room to another eg.
connection(garage,sidehall).
connection(sidehall,kitchen).
connection(kitchen,diningroom).
canget(X,Y):-connection(X,Y).
canget(X,Y):-connection(X,_),
write('player goes from '),write(X),write(' to '),write(Y),nl,
canget(_,Y).
Im trying to figure out how make it so the player can only get from one room to another when they have a specific item, such as you can only be in the kitchen when items = gloves.
canget(X,Y,Item):-connection(X,Y,Item),canbein(Y,Item).
canget(X,Y,Item):-connection(X,Somewhere,Item),canbein(Somewhere,Item),canget(Somewhere,Y,Item).
tried defining canbein with:
canbein(kitchen):- item(sword).
canbein(sidehall):- item(hat).
but that doesnt work!
Have defined my items as such, not sure if this is right either:
item(gloves,sword,helm,cheese).
Basically, have i declared my item values correctly?
How can i use the specific item value to make canget x to y false?
Thank you!
Well, I see a few problems with your code. Firstly, you call canbein with two arguments (from canget predicate). However, canbein is defined as single-argument predicate. Therefore, the call always fails as no canbein/2 predicate exists.
I suggest the following modification:
canbein(kitchen, sword).
canbein(sidehall, hat).
Than, the item definition is not required. Let's think about what happens during the unification of
canget(X,Y,Item) :- connection(X,Y,Item), canbein(Y,Item).
Let's assume the following setting X=sidehall, Y=kitchen, Item==sword. This predicate should be OK. Assuming the conection predicate is OK, prolog tries to find canbein(Y, Item) i.e. canbein(kitchen, sword) and it succeeds.
On the contrary, if the Item is different the unification fails, hence it works as expected.
The second problem is the item predicate. By your definition, it expects 4 arguments. That's nonsense, of course. You should declare it like
item(gloves).
item(sword).
item(helm).
item(cheese).
However, I don't think this predicate is necessary at all. Just to be clear, try to call item(X) and obtain all results (the four declared). Try it with the prior definition - what should you even ask for?
I hope it helps :)

Why do I have to specify an ExtPgm parameter for the Main Procedure?

My program, PKGDAYMONR has the control option:
ctl-opt Main( CheckDailyPackages )
The CheckDailyPackages procedure has the following PI:
dcl-pi *n ExtPgm( 'PGMNAME' );
As you can see the ExtPgm parameter is not the name of the program. In fact, it’s what came over in the template source and I forgot to change it. Despite the wrong name in ExtPgm, the program runs without a problem.
If I remove that parameter and leave the keyword as just ExtPgm, I get the following message:
RNF3573: A parameter is required for the EXTPGM keyword when the
procedure name is longer than 10.
If I drop ExtPgm from the Procedure Interface altogether, it also complains:
RNF3834: EXTPGM must be specified on the prototype for the MAIN()
procedure.
So why is it that I have to specify a parameter if it doesn't matter what value I enter?
O/S level: IBM i 7.2
Probably worth pursuing as a defect with the service provider; presumably for most, that would be IBM rather than a third-party, as they would have to contact IBM anyhow, given the perceived issue is clearly with their compiler. Beyond that, as my "Answer", I offer some thoughts:
IMO, and in apparent agreement with the OP, naming the ExtPgm seems pointless in the given scenario. I think the compiler is confused while trying to enforce some requirements in validations of the implicitly generated Prototype for the linear-main for which only a Procedure Interface is supplied; i.e. enforcing requirements that are appropriate for an explicit Prototype, but requirements that could be overlooked [thus are no longer requirements] in the given scenario.? I am suggesting that while the RNF3573 would seem appropriate for diagnosing EXTPGM specifications of an explicit Prototype, IMO that same effect is inappropriate [i.e. the validation should not be performed] for an implicit prototype that was generated by the compiler.
FWiW: Was the fixed-format equivalent of that free-form code tested, to see if the same or a different error was the effect? The following source code currently includes the EXTPGM specification with 'PGMNAME' as the argument [i.e. supplying any bogus value of 10-byte naming to supplicate the compiler, just as is being done in the scenario of the OP, solely to effect a successful compile], but could be compiled with the other variations with changes to the source, mimicking what was done with free-form variations, to test if the same\consistent validations and errors are the effect:
- just EXTPGM keyword coded (w/out argument); is RNF3573 the effect?
- the EXTPGM keyword could be omitted; is RNF3834 the effect?
- the D-spec removed entirely (if there are no parameters defined); ¿that was not one of the variations noted in the OP as being tried, so... the effect?
H MAIN(CheckDailyPackages)
*--------------------------------------------------
* Program name: CheckDailyPackages (PGMNAME)
*--------------------------------------------------
P CheckDailyPackages...
P B
D PI EXTPGM('PGMNAME')
/free
// Work is done here
/end-free
P CheckDailyPackages...
P E
I got a response from IBM and essentially Biswa was on to something, it simply wasn't clear (in my opinion) about the answer.
Essentially the EXTPGM is required on long Main procedure names in order to support recursive program calls.
This is the response I received from IBM explaining the reason for the scenario:
The incorrect EXTPGM would only matter if there was a call to the main
procedure (the program) within the module.
When the compiler processes the procedure interface, it doesn't know
whether there might be a call that appears later in the module.
EXTPGM keyword is used to define the external name of the program which you want to prototype. If you mention the EXTPGM then the program will be called dynamically.
Let us take an example in order to explain your query.
PGMA
D cmdExc PR ExtPgm('QSYS/QCMDEXC')
D 200A const
D 15P05 const
c callp cmdExc('CLRPFM LIB1/PF1':200)
C Eval *INLR = *ON
In the above example CmdExc used for the dynamic call to QSYS/QCMDEXC.
When we use the same program name as the EXTPGM parameter it acts as an entry point to the program when called from other programs or procedure.
But in any case when we mention any name as the sample parameter the EXTPGM will not give any error in compilation, but it gives the error during run time as it tries to resolve the name during run time.

Prolog List of Constants to String

i have a list in input: [asd,qweqwe,fsdf,lkasd]
As un can see from the code i want connect each constant of the list to output a single variable list.
i m using yap prolog, i consult this code and i write :- run.
the write function print out _G1233 and not 'asd,asd2,asd3,asd4'
why ? how i have to change the code for output me 'asd,asd2,asd3,asd4' ?
run :- toAtomicVars([asd,asd2,asd3,asd4],',',Out),
write(Out),nl.
toAtomicVars([],In,Out).
toAtomicVars([A|B],In,Out) :-
atomic_concat(A,In,Out1),
atomic_concat(',',Out1,Out2),
toAtomicVars(B,Out2,Out2).
you (should) get a warning like
Singleton variables: [In,Out]
Singleton variables: [Out]
that means that you dont really do anything with those variables:
toAtomicVars([],In,Out).
In and Out can be anything, so prolog just prints a dummy value, _Gsomething that means that the variable is not instantiated.
same thing happens in the second clause:
toAtomicVars([A|B],In,Out) :-
atomic_concat(A,In,Out1),
atomic_concat(',',Out1,Out2),
toAtomicVars(B,Out2,Out2).
you dont say anywhere what is that Out.
personally i think that it would be easier if you just printed each variable recursively and then print a comma, something like:
print_list([X]):-
write(X).
print_list([H|T]):-
write(H),
write(', '),
print_list(T).
but if you want to put commas in the list you should add a rule that defines Out.

Resources