Hello, !, the second program improved.
Okay, so in Prolog when we get user input at the prompt we usually need our user to be wise enough to close their input with a full-stop. Let's demonstrate, in order for this example to work in Tau Prolog you'll need to input a valid atom and terminate in a full-stop (the input will appear to reset but actually append until a full-stop is included). You can try greet/0
with your favorite Prolog implementation, it'll work in most.
% A writeln substitute for the browser
:- use_module(library(js)).
writeln(Text) :-
prop(alert, Alert),
apply(Alert, [Text], _).
greet :-
read(Name),
atom(Name),
atomic_list_concat(['Hello, ', Name, '!'], Msg),
writeln(Msg).
greet.
But what if our users weren't so wise? Wouldn't it be nice if you could type in your name without a full-stop? We can replicate the above using JavaScript to compare. In this example you can write your name with a capital letter, without escaping it in single quotes first, and without a full-stop: like most people would.
% A writeln substitute for the browser
:- use_module(library(js)).
writeln(Text) :-
prop(alert, Alert),
apply(Alert, [Text], _).
prompt(Msg, X) :-
prop(prompt, Prompt),
apply(Prompt, [Msg], X).
greet :-
prompt('What\'s your name?', Name),
atomic_list_concat(['Hello, ', Name, '!'], Msg),
writeln(Msg).
greet.
That's great and all, except we're hijacking JavaScript to do it, what we need is a solution that'll work in the terminal. Here's one solution that works in SWI-Prolog:
read_string(String) :-
current_input(Stream),
read_string(Stream, '\n', ' \r', Sep, String0),
( Sep \== -1
-> String = String0
; String0 == ""
).
greet :-
read_string(Name),
format("Hello, ~w!", Name).
That's not going to appear in a beginner's book anytime soon! Let's break it down.
First we get the current_input(Stream)
, which by default is your prompt. We then use read_string/5
. It reads from the Stream
up to '\n'
, which is when your user hit return. The argument ' \r'
are the characters stripped off the left and right of the string. Sep
is -1
if the user terminated the input (for example by Ctrl+D), otherwise we can unify String0
with String
and return that.
Try this out, you can skip the full-stop! We're also reading a string, so case is irrelevant. If you like it, there's a more versatile implementation read_line_to_string/2
that can cope with files and other streams, as well as related predicates in the readutil library.