I'm new to Prolog, and trying to implement an example from a textbook. I have been able to get the example working (through definite help from previous Stack Overflow posts!) finally, but now it is asking me to verify the user input: "Modify the given decision tree program, so that when the user responds to a question with an illegal answer, the system will ask him/her to reenter an answer which is among the specified choices."
In the below program, for marital status, the specified only options considered in the decision tree are "single" or "married." If you enter anything else, the goal is to get you to reenter your decision.
This is not working for me. My code is below:
:-dynamic income/2.
:-dynamic marital_status/2.
:-dynamic mortgage/2.
:-dynamic age/2.
marital_status(joe,married).
income(joe,60000).
mortgage(joe,20000).
age(joe,45).
main(X,Z):-var(X), write('what is your name?'),read(X), invest(X,Z),!.
main(X,Z):-invest(X,Z),!.
ask_marital_status(X,Y):-marital_status(X,Y).
ask_marital_status(X,Y):-not(marital_status(X,Y)), write('what is your marital status: married or single?'), read(Y), nl, asserta(marital_status(X,Y)).
ask_marital_status(X,Y):-Y \=married, Y \=single, write('what is your marital status: married or single?'), read(Y), nl, asserta(marital_status(X,Y)).
%ask_marital_status(X,Y):-Y \= married; Y \= single, ask_marital_status(X,Y).
ask_income(X,Y):-income(X,Y).
ask_income(X,Y):-not(income(X,Y)),write('what is your annual income?'), nl, read(Y), asserta(income(X,Y)).
ask_mortgage(X,Z):-mortgage(X,Z).
ask_mortgage(X,Z):-not(mortgage(X,Z)), write('what is your mortgage?'), read(Z), nl, asserta(mortgage(X,Z)).
ask_age(X,A):-age(X,A).
ask_age(X,A):-not(age(X,A)), write('what is your age?'), read(A), nl, asserta(age(X,A)).
moderate_risk(X):-ask_marital_status(X,Y), Y=married, ask_income(X,I), I=<50000, ask_mortgage(X,Z), Z=<50000,!.
moderate_risk(X):-ask_marital_status(X,M), M=married, ask_income(X,I), I=<50000,!.
moderate_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I=<35000,!.
stable_risk(X):-ask_marital_status(X,M), M=married, ask_income(X,I), I=<50000, ask_mortgage(X,Z), Z>50000,!.
stable_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000, ask_age(X,A), A>50, !.
high_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000, ask_age(X,A), A=<50, !.
invest(X,oil):-stable_risk(X),!.
invest(X,telecommunications):-moderate_risk(X),!.
invest(X,computers):-high_risk(X),!.
The third "ask_martial_status" is my current attempt to get the user to reenter their decision, but it is not working. I have tried it with Prolog's AND operator(,) and their or operator (;) - neither make a difference (for what I place in between Y\= married and Y\=single). When I enter erroneous input, I just get "false" returned. Below is an example:
?- main(X,Z).
what is your name?logan.
what is your marital status: married or single?|: widowed.
false.
The commented out line (with the %) was a previous attempt to get the program working that also failed. I'm surprised I wasn't able to find a quick YouTube video / article to read when I Google'd this issue. Could anyone help me out here?
The traditional way of reading and validating user input is to use the following template:
ask(Data) :-
repeat,
write(Prompt),
read(Data),
valid(Data),
!.
Applying this template to your case, we can write:
ask_marital_status(Status) :-
repeat,
write('What is your marital status (married or single)?'),
read(Status)
( Status == married
; Status == single
),
!.
As a general rule, is best practice to separate asking the user input from processing the input (asserting a fact in your case).
High-level solutions would use message printing and question asking mechanisms for user interaction (see e.g. https://logtalk.org/2019/11/14/abstracting-user-interaction.html). But that's a more advanced topic.
You can solve your problem in this way (snippet of the involved prefocate):
ask_marital_status(X,Y):-
\+ marital_status(X,Y),
write('what is your marital status: married or single?'),
read(Y1),
( (Y1 == single ; Y1 == married) ->
Y = Y1,
asserta(marital_status(X,Y));
ask_marital_status(X,Y)
).
You can check if the value you read (Y1) is single or married with (Y1 = single ; Y1 = married) (; means or). Then, if so (->) you proceed with the rest of the predicate. Otherwise, (after the ; next to asserta/1) you call recursively marital_status/2.
EDIT: thanks to Paulo Moura's comment, =/2 (unification) must be replaced with ==/2 (equality), in order to make the code behave as expected.
This code:
FOO:
"Hey".say;
for <1 2> {
say "1";
last FOO
}
Prints
Hey
1
Control flow commands not allowed in toplevel
The last error message is eliminated if "Hey".say is taken off; this probably means that what the error is actually saying is that non control flow commands are not allowed right behind a label. But the documentation (which needs to be improved cites loops as an "example", and the grammar indicates it should be in front of a statement. So the question is: can it be used for if statements, or just loops?
The error is different if you have this code inside another scope:
{
FOO:
"Hey".say;
for <a b> {
.say;
last FOO
}
}
# Hey
# a
# labeled last without loop construct
which is also LTA in that it doesn't mention the name of the label.
But in short: Perl 6 doesn't currently have a goto. Currently, labels are only usable as a way to specify which loop construct you want to next, redo to or last out of. By putting a statement between the label and the loop construct, you're effectively using it as a goto, which is still Not Yet Implemented.
But indeed a ticket about the LTAness of both errors, seems in place for me.
Also, using the FIRST phaser as an alternative, seems to have the same issue:
FOO:
for <a b> {
FIRST "Hey".say;
.say;
last FOO;
}
# Hey
# a
# labeled last without loop construct
But runs fine without the specific label:
FOO:
for <a b> {
FIRST "Hey".say;
.say;
last;
}
# Hey
# a
The latter issue most definitely is worth a rakudo issue: added as https://github.com/rakudo/rakudo/issues/2699 .
I'm trying to create a many to many table using Groundhog in Haskell, which basically looks like this if I cut away all the other logic I have:
data FooRow = FooRow {
fooRowUUID :: UUID
}
deriving instance Show FooRow
data BarRow = BarRow {
barRowUUID :: UUID
}
deriving instance Show BarRow
data FooToBarRow = FooToBarRow {
fooToBarRowUUID :: UUID,
fooToBarRowFoo :: DefaultKey FooRow,
fooToBarRowBar :: DefaultKey BarRow
}
deriving instance Show FooToBarRow
Now, trying to define operations, I can get and insert all of these records just fine, however I'm not sure how to go from having a FooRow, with it's ID, and then get all the related BarRows by way of the many to many table. Right now I've played with something like this:
getBarsForFoo fooID = do
barKeys <- project
(FooToBarRowBarField)
(FooToBarRowFooField ==. (Foo_FooKey fooID))
select $ (BarRowUUIDField `in_` barKeys)
However this doesn't typecheck, with the error:
Couldn't match type 'UUID' with 'BarRow'
Inspecting just the results of the project with putStrLn, I can see that the type of barKeys is:
[Bar_BarKey UUID]
but I don't quite understand how to make use of that within my query. I don't see any examples like this in the Groundhog documentation, so I'm hoping someone will be able to put me on the right path here.
I'm quite certain there are more efficient ways to go about this (there's going to be a bunch of underlying queries with this approach), but this does at at least get the job done for now.
getBarsForFoo fooID = do
barKeys <- project
(FooToBarRowBarField)
(FooToBarRowFooField ==. (Foo_FooKey fooID))
q <- mapM (getBy) barKeys
return (catMaybes q :: [BarRow])
I have a velocity template (in a Confluence user macro) that looks like:
## This macro takes a jiraissues macro in the body with "Show Total Only" configured to TRUE.
## It then parses the return and puts a green check if the number returned is ZERO or a red X otherwise.
## #noparams
#set ($start = $body.indexOf("{") + 1)
#set ($end = $body.indexOf("}") )
Printf debugging...<br />
body.substring($start, $end) = $body.substring($start, $end) <br />
<ac:rich-text-body>
<ac:image ac:thumbnail="false">
## BUG BUG This substring is ALWAYS zero. Dunno why.
#if ($body.substring($start, $end) == "0")
<ri:url ri:value="/images/icons/emoticons/check.png" />
#else
<ri:url ri:value="/images/icons/emoticons/error.png" />
#end
</ac:image>
</ac:rich-text-body>
This template has a nested other velocity template that is configured by the user to query a DB and return the number of bugs that match some criteria. The idea is that if the number returned is ZERO, then everything is hunkydory. Otherwise, well... you get the picture.
Now, there's something CLEARLY screwed up in my thinking.
The $body string seems to returns something that looks like {0} issues.
The {0} seems like a variable or something, but hell if I can find any documentation.
Questions
Which template gets evaluated first?
Can I even base the logic of one template on the output of another?
Why is my life like this? Never mind, I know the answer to that one.
A string like {0} suggests that what you see isn't the actual end result, but a message template that is supposed to be filled in with real data. And to me it looks like a key used by MessageFormat, but it could be something else.
Do you happen to have the code for the inner macro as well?
I'm currently learning to code Erlang. I have a web application on top of Chicago Boss.
I have a model called Todo, and I would like to offer CRUD operations on it as a REST API.
In my PUT method I have this code:
index('PUT', [Id]) ->
Todo = boss_db:find(Id),
Body = element(2, mochijson:decode(Req:request_body())),
%% Set the new values
NewTodo = Todo:attributes([
{subject, proplists:get_value("subject", Body)},
{done, proplists:get_value("done", Body)}
])
,
{json, [{todo, element(2, NewTodo:save())}]}.
How can I optimize this code fragment? Or is this already the best possible?
Is there some "smarter" way to change the keys of a proplist to atom keys? Like this:
[{"subject", "Foo"}] -> [{subject, "Foo"}].
I also find it kind of tedious to assign a Todo variable and then have a NewTodo. Sadly I can't find some good example Erlang Chicago Boss apps on github that I can check out.
You always can do something like this:
t([{"subject", V}|T]) -> [{subject, V}|t(T)];
t([{"done" , V}|T]) -> [{done, V}|t(T)];
t([_ |T]) -> t(T) ; % optional garbage ignoring clause
t([]) -> [].
But I doubt, it will be significant speed improvement in your case.
May be you will be able squeeze last bit from this:
-compile({inline, [t/1]}).
t(L) -> t(L, []).
t([{"subject", V}|T], A) -> t(T, [{subject, V}|A]);
t([{"done" , V}|T], A) -> t(T, [{done, V}|A]);
t([_ |T], A) -> t(T, A); % optional garbage ignoring clause
t([], A) -> A.
Which is worth only for benchmark code competitions ;-) (Note there is not lists:reverse/1 call in last clause. It would be ruining improvement form previous version.)
P.S.: If you think I'm micro-optimization freak, you are right, so I would replace lists:reverse/1 call with lists:reverse/2 to use BIF directly and save some more time ;-)
Unfortunately I cannot comment on Hynek's answer, but as Erlang newbie, my first guess would have been to go for something along the lines of:
lists:map(fun({A, B}) -> {list_to_atom(A), B} end, [X || {Y, Z}=X <- List, is_list(Y)]).
You cannot really avoid the NewTodo assignment
How about
index('PUT', [Id]) ->
Body = element(2, mochijson:decode(Req:request_body())),
OldTodo = boss_db:find(Id),
NewTodo = OldTodo:attributes([ {list_to_atom(A),B} || {A,B}<-Body ]),
{json, [{todo, element(2, NewTodo:save())}]}.