0

Below are the codes I came up with. However, there are two problems here. First, only first value of X is displayed which is 1. Second, if Y is false, it doesn't jump back to menu1. Hope to get some help in this.

 time(office_hour,1).
 time(office_hour,2).
 menu1 :- 
   write('Input time'),nl,
   read(Y),nl,time(Y,X),nl,write(X),nl,menu1.

This is the example of the scenario. As seen below, only value 1 is shown. How to display value 2 too? Sry I'm just a newbie

?-menu1.
Input time
office_hour.
1.
Input time
Kimchi
  • 7
  • 3
  • You should post an example of the behaviour also. In particular, what is it you type in? If it is not `office_hour` then `time/2` will fail before it calls `menu1/0`. – Tomas By Dec 18 '17 at 11:28
  • sry, I updated my post already. Also what is this `time/2` and `menu1/0` mean? I do not recall any of such term from my lecturer. – Kimchi Dec 18 '17 at 11:36
  • @Kimchi it's in Prolog documentation if you look at it. The `/n` means `n` arguments. So `time/2` is `time` with 2 arguments. If there were a `time` with 3 arguments, it would be a different predicate and described as `time/3`. – lurker Dec 18 '17 at 11:47
  • I am voting to close this question on the basis of it being unclear what you're asking since answers have been offered that appear to address it, but none accepted. – lurker Dec 19 '17 at 17:24

2 Answers2

0

You need to allow Prolog to backtrack to get all of the solutions. The problem with your predicate is that it does a recursive call before it can backtrack. Also, you continue to recurse one level deeper for the next menu prompt which is probably not good practice since it continually consumes more stack as it responds to user inputs.

Here's another approach, using the repeat/0 predicate along with fail/0. repeat/0 simply succeeds which allows to re-query for solutions during backtracking. And fail/0 always fails, which forces backtracking. It's a common way to do a continual repeat loop and works well for looping on a menu. I've also adjusted the nl/0 usage a bit to make the output a little neater, and I renamed time/2 since it is just too generic a name and could potentially collide with a system predicate.

item_time(office_hour,1).
item_time(office_hour,2).

menu1 :-
    repeat,
    nl, write('Input time'), nl,
    read(Y),
    item_time(Y, X),
    write(X), nl,
    fail.

This will yield:

| ?- menu1.

Input time
office_hour.
1
2

Input time
foo.

Input time
...

What happens here is that fail/0 will cause the predicate clause to backtrack through the write(X), nl and to the time(Y, X) which will come up with the alternate solutions, succeed on those solutions, and then move forward to the write(X), nl again. If time(Y, X) finds no more solutions, then it finally fails and the clause backtracks all the way back to the repeat/0 call, which always succeeds. That results in the execution moving forward again to the nl, write('Input time'), ....

As you can see, inputting something unrecognized just re-prompts. To make this more complete, you could add atoms that are recognized as a "quite" and you could write a diagnostic message if you get input that doesn't exist in your database. That would be a good exercise for learning.

lurker
  • 56,987
  • 9
  • 69
  • 103
  • may i know what does `fail/0` do? i googled and it says 'always fail'... – Kimchi Dec 18 '17 at 12:12
  • You have noticed that predicates can fail? Like if you call `time/2` with something other than `office_hour` as first parameter. It's like that but independent of variables. It just always fails. It is useful if you want to do some side effects like printing before the failure. – Tomas By Dec 18 '17 at 12:26
  • @Kimchi I augmented my answer to explain fail a little. A common Prolog pattern is the "repeat-fail loop". – lurker Dec 18 '17 at 13:10
  • 1
    @Kimchi a quick Google search of "Prolog fail predicate" comes up with [What are the uses of the fail predicate in Prolog?](https://stackoverflow.com/questions/3001825/what-are-the-uses-of-the-fail-predicate-in-prolog). As I mentioned in my augmented answer, the `fail/0` forces backtracking. Backtracking occurs when a predicate call fails. – lurker Dec 18 '17 at 13:39
  • @Kimchi if I answered your question, perhaps you could click on the checkmark to accept my answer. – lurker Dec 19 '17 at 02:57
  • Thanks, I am new here so pardon for my mistake – Kimchi Dec 20 '17 at 00:45
  • @Kimchi no worries. If you click on the help link at the bottom of the page, there's some good information on how to work in the stackoverflow.com site. – lurker Dec 20 '17 at 03:25
0

The second problem:

menu1 :- 
  write('Input time'),nl,
  read(Y),nl,
  ( time(Y,X) ->
    write(X),nl
  ; write('bad input'),nl ),
  menu1.
Tomas By
  • 1,396
  • 1
  • 11
  • 23
  • what does `(time(Y,Z) -> ...)` actually does? i mean the parentheses – Kimchi Dec 18 '17 at 12:15
  • what if i just write `time(Y,X) -> write(X),nl ; write('bad input'),nl` without parentheses? i do know `->` means if-then-else – Kimchi Dec 18 '17 at 12:27
  • Ah, ok. It depends on what is outside that expression I think. It will probably work, but may be wrong if there are other special operators nearby. It is nice and easily readable to use brackets around all if-then-else expressions. – Tomas By Dec 18 '17 at 12:31
  • You can always add extra brackets, like in maths expressions. – Tomas By Dec 18 '17 at 12:32