library(ask)
The file library(ask)
defines a set of commands for asking questions
whose answer is a single character, and for asking for file names
(see lib-ofi-oth-ask).
library(ask)
uses several commands from library(prompt)
,
but if you want to use them in your program you should
explicitly include the directive
:- ensure_loaded(library(prompt)).
in your program. The principal such command is prompt/1
, which
is used to print the question or prompt.
yesno(
+Question)
write/1
) to the terminal, regardless of
the current output stream, and reads an answer.
The prompt is followed by ?
, so you should not put a question
mark in the question yourself. The answer
is the first character typed in response; anything following on the
same line will be thrown away. If the answer is y or Y, yesno/1
succeeds. If the answer is n or N, yesno/1
fails. Otherwise it
repeats the question. The user has to explicitly type a y or n
before it will stop. Because the rest of the line is thrown
away, the user can type yes, Yes, You'd better not, and so
forth with exactly the same effect as a plain y. If the user
just presses <RET>, that is not taken as yes.
yesno(
+Question,
+Default)
yesno/1
except that
For example,
yesno('Do you want an extended trace', yes)
prints
Do you want an extended trace [y]? _
and leaves the terminal's cursor where the underscore is. If the
user presses <RET>, this call to yesno/1
will succeed.
If the user answers yes it will succeed. If the user answers
no it will fail. If the first non-layout character of the user's answer
is neither n, N, y, nor Y, the question will be
repeated.
ask(
+Question,
-Answer)
yesno/1
would, and
reads a single character Answer. Answer must be a "graphic"
character (a printing character other than space). ask/2
will
continue asking until it is given such a character. The remainder
of the input line will be thrown away.
ask(
+Question,
+Default,
-Answer)
yesno/2
does,
and mentions the default in brackets just before the question
mark. If the user presses carriage return, Default will be
returned as his Answer. Answer can be instantiated, in which
case the call to ask/2
or ask/3
will fail if the user does not
give that answer. For example, yesno/2
could (almost) have been
defined as
yesno(Question, Default) :- ask(Question, Default, 0'y).
ask_chars(
+Prompt,
+MinLength,
+MaxLength,
-Answer)
:
) are added to the Prompt,
so don't add such punctuation yourself.
The end-user can find out what sort of input is required by typing
a line that starts with a question mark. Therefore it is not possible
to read such a line as data. See prompted_line/2
in library(prompt)
.
Examples:
| ?- ask_chars('Label', 1, 8, Answer). Label: 213456789 Please enter between 1 and 8 characters. Do not add a full stop unless it is part of the answer. Label: four Answer = "four" | ?- ask_chars('Heading', 1, 30, Answer). Heading: ? Please enter between 1 and 30 characters. Do not add a full stop unless it is part of the answer. Heading: three leading spaces Answer = " three leading spaces"
ask_number(
+Prompt, +Default, -Answer)
_
, and plus signs +
.
For example, the input + 123_456
would be treated as if the
user had typed 123456
. The conversion is done by number_chars/2
.
If the user entered an integer, Answer will be unified with an
integer. If the user entered a floating-point number, Answer will
be unified with a floating-point number. No conversion is done.
If the line contains only "garbage" characters and there is a
Default argument, Answer is unified with Default.
This happens regardless of whether or not Default is a number.
If the input is unacceptable, the question will be repeated after
an explanation of what is expected. The user can type ? for help.
Examples:
| ?- ask_number('Pick a number', X). Pick a number: ? Please enter a number followed by RETURN Pick a number: 27 X = 27 | ?- ask_number('Say cheese', X). Say cheese: Please enter a number followed by RETURN Say cheese: 3 . 141 _ 593 X = 3.14159 | ?- ask_number('Your guess', '100%', X). Your guess [100%]: 38. Please enter a number followed by RETURN Your guess [100%]: 38 X = 38 | ?- ask_number('Your guess', '100%', X). Your guess [100%]: <RET> X = '100%'
ask_number(
+Prompt,
+Lower,
+Upper[,
+Default],
-Answer)
ask_between/[4,5]
and
ask_number/[2,3]
. They write the prompt to the terminal, read a line from
it in response, throw away "garbage" characters, try to parse the result
as a number, and check that it is between the Lower and Upper bounds.
Lower and Upper may severally be integers or floating point
numbers. Answer will be unified with an integer if the user typed
an integer, with a floating-point number if the user typed a floating-point
number, or with whatever Default happens to be if there is a
Default and the user entered an empty line. If you want a floating-point
result whatever the user typed, you will have to do your own
conversion with is/2
.
Examples:
| ?- ask_number('Enter temperature in Fahrenheit', 32.0, 212.0, 77.0, Temp). Enter temperature in Fahrenheit [77.0]: 10 Please enter a number between 32.0 and 212.0 followed by RETURN Enter temperature in Fahrenheit [77.0]: 68 Temp = 68
ask_file(
+Question,
-Filename)
ask_file/3
.
ask_file(
+Question,
+Mode,
-FileName)
ask_file/3
just fails; an empty filename is taken as an indication
that the user has finished entering file names. A reply
beginning with a question mark will cause a brief help message to be
printed (explaining that a filename is wanted, and how to enter one),
and the question will be repeated. Otherwise, ask_file/3
checks that
the file can be opened in the mode specified by Mode (read
,
write
, or append
).
If it is not possible to open the file in mode Mode,
the operating system's error
result is reported and the question is repeated. If it is possible
to open the file in this mode, the name of the file is returned
as FileName.
However, ask_file/3
does not open the file for you, it simply checks that
it is possible to open the file. Here is an example "dialogue":
| ?- ask_file('Where should the cross-reference go? ', write, File). Where should the cross-reference go? ? Please enter the name of a file that can be opened in write mode, followed by <RET>. To end this operation, just type <RET> with no filename. Where should the cross-reference go? call.pl ! Permission error: cannot access file 'call.pl' ! O/S error : Permission denied ! goal: can_open_file('call.pl',write,warn)
| ?- ask_file('Where should the cross-reference go? ', write, File). Where should the cross-reference go? call.xref File = 'call.xref' | ?- ask_file('Next file: ', read, File). Next file: call.pl ! Permission error: cannot access file 'call.pl' ! O/S error : Permission denied ! goal: can_open_file('call.pl',read,warn)
| ?- ask_file('Next file: ', read, File). Next file: call.xref ! Existence error in can_open_file/3 ! file call.xref does not exist ! O/S error : No such file or directory ! goal: can_open_file('call.xref',read,warn)
Points to note:
ask_file/3
does not add a question mark and space to the prompt; you
must put them in the question yourself.
ask_file/3
found that it was possible to open call.xref
for output,
it did not open it, so the second call to ask_file/3
could not find any
such file.
ask_between(
+Prompt,
+Lower,
+Upper[,
+Default],
-Answer)
p(X) :- ask_between('Number of samples',1,20, [none],X), integer(X).
the following conversation might take place.
| ?- p(X). Number of samples [none]: ? Please enter an integer between 1 and 20 Do not add a full stop. Number of samples [none]: 0 Please enter an integer between 1 and 20 Do not add a full stop. Number of samples [none]: 9 X = 9 | ?- p(X). Number of samples [none]: <RET> no
The prompt that is printed is Prompt
[
Default]:
if
there is a Default
argument, Prompt
:
otherwise, so that you can use the same prompt
whether or not there is a default argument.
ask_oneof(
+Prompt,
+Constants[,
+Default],
-Answer)
prints Prompt on the terminal, and reads a line in response.
Constants
should be a list of constants (terms that are acceptable as the first
argument of name/2
). If the user's response is the full name of one
of the
constants, Answer is unified with that constant. Failing that, if the
user's response is a prefix of exactly one of the constants, Answer is
unified with that constant. If the response is just <RET>,
and there is
a Default argument, Answer is unified with Default (which need
not be a
constant, nor need it be an element of Constants). If nothing else works,
the user is told what sort of response is wanted, and is prompted again.
The prompt that is printed is Prompt
[
Default]:
if there
is a Default
argument, Prompt
:
otherwise, so that you can use the same prompt
whether or not there is a default argument.
You should find it straightforward to define your own simple queries using this kit. As a general rule, try to arrange things so that if the user types a question mark s/he is told what sort of response is wanted. All the queries defined in this section do that.
The commands for reading English sentences do nothing special when their input is a single question mark. Here is an example of how you can build a query from them that does something sensible in this case.
ask_sentence(Prompt, Sentence) :- repeat, prompt(Prompt), read_in(X), ( X = [?] -> format(user_output, 'Please enter an English sentence.~n', []), fail ; true ), !, Sentence = X.