Input 序言:如何验证用户输入?

Input 序言:如何验证用户输入?,input,prolog,verify,Input,Prolog,Verify,我不熟悉Prolog,并试图实现教科书中的一个示例。我终于能够让示例正常工作(通过前面的堆栈溢出帖子的明确帮助!),但现在它要求我验证用户输入:修改给定的决策树程序,以便当用户以非法答案回答问题时,系统将要求他/她重新输入指定选项中的答案 在下面的程序中,对于婚姻状况,决策树中考虑的唯一指定选项是“单身”或“已婚”。如果您输入任何其他内容,目标是让您重新输入您的决策 这对我不起作用。我的代码如下: :-dynamic income/2. :-dynamic marital_status/2. :

我不熟悉Prolog,并试图实现教科书中的一个示例。我终于能够让示例正常工作(通过前面的堆栈溢出帖子的明确帮助!),但现在它要求我验证用户输入:修改给定的决策树程序,以便当用户以非法答案回答问题时,系统将要求他/她重新输入指定选项中的答案

在下面的程序中,对于婚姻状况,决策树中考虑的唯一指定选项是“单身”或“已婚”。如果您输入任何其他内容,目标是让您重新输入您的决策

这对我不起作用。我的代码如下:

:-dynamic income/2.
:-dynamic marital_status/2.
:-dynamic mortgage/2.
:-dynamic age/2.

marital_status(joe,married).
income(joe,60000).
mortgage(joe,20000).
age(joe,45).

main(X,Z):-var(X), write('what is your name?'),read(X), invest(X,Z),!.
main(X,Z):-invest(X,Z),!.
ask_marital_status(X,Y):-marital_status(X,Y).
ask_marital_status(X,Y):-not(marital_status(X,Y)), write('what is your marital status: married or single?'), read(Y), nl, asserta(marital_status(X,Y)).
ask_marital_status(X,Y):-Y \=married, Y \=single, write('what is your marital status: married or single?'), read(Y), nl, asserta(marital_status(X,Y)).
%ask_marital_status(X,Y):-Y \= married; Y \= single, ask_marital_status(X,Y).
ask_income(X,Y):-income(X,Y).
ask_income(X,Y):-not(income(X,Y)),write('what is your annual income?'), nl, read(Y), asserta(income(X,Y)).
ask_mortgage(X,Z):-mortgage(X,Z).
ask_mortgage(X,Z):-not(mortgage(X,Z)), write('what is your mortgage?'), read(Z), nl, asserta(mortgage(X,Z)).
ask_age(X,A):-age(X,A).
ask_age(X,A):-not(age(X,A)), write('what is your age?'), read(A), nl, asserta(age(X,A)).

moderate_risk(X):-ask_marital_status(X,Y), Y=married, ask_income(X,I), I=<50000, ask_mortgage(X,Z), Z=<50000,!.
moderate_risk(X):-ask_marital_status(X,M), M=married, ask_income(X,I), I=<50000,!.
moderate_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I=<35000,!.
stable_risk(X):-ask_marital_status(X,M), M=married, ask_income(X,I), I=<50000, ask_mortgage(X,Z), Z>50000,!.
stable_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000, ask_age(X,A), A>50, !.
high_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000, ask_age(X,A), A=<50, !.

invest(X,oil):-stable_risk(X),!.
invest(X,telecommunications):-moderate_risk(X),!.
invest(X,computers):-high_risk(X),!.

注释掉的行(带%)是之前试图让程序运行的一次尝试,但也失败了。我很惊讶,当我用谷歌搜索这个问题时,没有找到一个快速的YouTube视频/文章可供阅读。这里有人能帮我吗?

你可以用这种方式解决你的问题(相关预定位的片段):

您可以检查您读取的值(
Y1
)是否是
单身
已婚
(Y1=单身;Y1=已婚)(
表示或)。如果是这样(
->
)则继续执行谓词的其余部分。否则,(在
资产/1
旁边的
后面)您可以递归调用
婚姻状况/2


编辑:由于Paulo Moura的评论,
=/2
(统一)必须替换为
=/2
(平等),以使代码按预期运行。

阅读和验证用户输入的传统方法是使用以下模板:

ask(Data) :-
    repeat,
        write(Prompt),
        read(Data),
    valid(Data),
    !.
将此模板应用于您的案例,我们可以编写:

ask_marital_status(Status) :-
    repeat,
        write('What is your marital status (married or single)?'),
        read(Status)
    (   Status == married
    ;   Status == single
    ),
    !.
一般来说,最好的做法是将询问用户输入与处理输入(在您的案例中断言事实)分开


高级解决方案将使用消息打印和提问机制进行用户交互(参见示例)。但这是一个更高级的主题。

请注意,
write
read
不是真正的文本I/O谓词;它们是术语序列化/非序列化谓词。因此,输入必须是一个术语,并以
结尾。相应的文本I/O谓词是(可移植的),并且来自的谓词用于读取(不可移植,仅限SWI Prolog)。@DavidTonhofer Logtalk提供了一个可移植的
读卡器
库,该库提供了与SWI Prolog
库(readutil)类似的功能
。有关API文档,请参阅。@PauloMoura我将不得不看一看整个语言。尽管我不得不说我不知道先学习哪种语言。我已经在图版上标记了Clojure和R.:-)作为答案。这很有效,您的解释也帮助我理解了它(不过不要描述其他建议的解决方案!)。谢谢。应使用术语相等(
=/2
)而不是术语统一(
=/2
)来测试已读术语!如果用户输入例如
已婚。
,则代码将假定用户输入的是
单身
,而不是重复问题。您注意到您的程序了吗?请不要通过重新发布格式错误的文本来忽略它。如果输入来自
/dev/null
ask(Data) :-
    repeat,
        write(Prompt),
        read(Data),
    valid(Data),
    !.
ask_marital_status(Status) :-
    repeat,
        write('What is your marital status (married or single)?'),
        read(Status)
    (   Status == married
    ;   Status == single
    ),
    !.