循环,直到它在prolog中输入有效值

时间:2014-04-26 13:03:47

标签: validation prolog

我是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).

等等。

我知道如何验证上述输入。但我想知道的是如何循环输入过程,直到它输入有效值。例如,如果用户输入无效年份,则应显示错误消息(例如,无效年份),并且应该让他/她再次输入,而不从头开始。

3 个答案:

答案 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)