我是prolog的新手。我只有Prolog的基础知识。 我在Prolog中编写了这段代码,我不知道如何实现这一部分。
我希望有人进入他/她的生日,并根据他/她的生日做其他计算。在计算值之前,我想验证他/她输入的内容。
例如我写了这段代码:
go:-write('Enter your name:'),nl,
read(Name),nl,
write('Enter your birth year:'),nl,
read(Year),nl,
write('Enter your birth month:'),nl,
read(Month),nl,
write('Enter your birth date:'),nl,
read(Date).
等等。
我知道如何验证上述输入。但我想知道的是如何循环输入过程,直到它输入有效值。例如,如果用户输入无效年份,则应显示错误消息(例如,无效年份),并且应该让他/她再次输入,而不从头开始。
答案 0 :(得分:3)
如果输入无效,另一种方法是使用repeat
返回。您可以使用提示编写用于用户输入的谓词:
read_input(Prompt, Value, CheckPred, ErrorMsg) :-
repeat,
format('~w:~n', [Prompt]),
read(Value),
( call(CheckPred, Value)
-> true, !
; format('ERROR: ~w.~n', [ErrorMsg]),
fail
).
go :-
read_input('Enter your name', Name, check_name, 'Invalid name'),
read_input('Enter your birth year', Year, check_year, 'Invalid year'),
read_input('Enter your birth month', Month, check_month, 'Invalid month'),
read_input('Enter your birth date', Date, check_date, 'Invalid date'),
% Do stuff with Name, Year, Month, Date...
.
创建检查器谓词:
check_name(Name) :- ...
check_year(Year) :- ...
check_month(Month) :- ...
check_date(Date) :- ...
您可以轻松地对此进行扩展,以便check_name
也可以进行一些修复"比如大写名字。 (你有check_...
两个参数,等等。)
ADDENDUM - 带有修复的参数检查
read_input(Prompt, Res, CheckPred, ErrorMsg) :-
repeat,
format('~w:~n', [Prompt]),
read(Value),
( call(CheckPred, Value, Res)
-> true, !
; format('ERROR: ~w.~n', [ErrorMsg]),
fail
).
% Check argument, and provided "fixed-up" argument xxxOut
check_name(Name, NameOut) :- ...
check_year(Year, YearOut) :- ...
check_month(Month, MonthOut) :- ...
check_date(Date, DateOut) :- ...
但是,我会建议允许用户输入整个日期并解析它。 SWI Prolog有一些日期谓词可以用于此目的。然后,您可以使用上面的日期替换年,月和日期;对于DateOut
,您可以使用birthdate(Month, Day, Year)
这样的术语。
答案 1 :(得分:2)
如果输入的值不正确,您可以使用尾递归:
get_data(X,Y) :-
ask_user(Z,T),
(validate(Z,T) ->
(X = Z, Y = T);
get_data(X,Y)).
c -> t ; f
是if-then-else模式。如果满足条件c
,则执行t
(从而将输入的数据与参数绑定),否则,使用尾递归来重试。
你当然可以争辩说这个调用会增加堆栈,但是如果执行尾递归,高级Prolog编译器不会在调用堆栈上创建额外的调用帧。
答案 2 :(得分:2)
您可以创建一个谓词,并递归调用它,直到得到正确的答案:
read_name(Name) :-
write('Your name: '),
read(TmpName),
((atom_codes(TmpName, L), length(L, N), N > 5) ->
(Name = TmpName) ;
(write('Error!'), nl, read_name(Name))
).
在这里,我只检查名称是否包含至少6个字符(N > 5
),但您可以根据需要替换它。
if else的语法是:
(Conditions -> ActionIfTrue ; ActionIfFalse)