Prolog 如何检查某个变量是否返回谓词中的内容

Prolog 如何检查某个变量是否返回谓词中的内容,prolog,Prolog,假设我有如下事实: airport(nyc,'newyork'). ?- main(_). Airport? wdc. Day? |: 1. Month? |: 2. Year? |: 2000. we have found something awesome true. 如果用户输入的机场不存在,我想显示一条消息 我的尝试: isAirport(Air) :- airport(Air,T), (var(T) -> true ;

假设我有如下事实:

airport(nyc,'newyork').
?- main(_).

Airport? wdc.

Day? |: 1.

Month? |: 2.

Year? |: 2000.
we have found something awesome
true.
如果用户输入的机场不存在,我想显示一条消息

我的尝试:

isAirport(Air)  :-
      airport(Air,T),
     (var(T) -> true 
      ; 
       write('Airport not found'),
       fail
      ).

但是,这似乎不起作用。

在下面的代码中,如果在数据库中找不到机场,则错误地假设t将保持未绑定状态:

airport(Air, T)
实际上,对airport(Air,T)的调用将使isAirport(Air)立即失败,您的var(T)和其他部分将根本不会执行

请尝试以下代码:

isAirport(Air) :-
    airport(Air, _T), ! ; write('Airport not found'), fail.

首先,让我们看看如果首先查询连词(运算符),会发生什么:

这意味着,
isAirport(abc)
在尝试
airport(abc,
)后直接失败,而不计算谓词的其余部分。在许多情况下,您可以不用显式的if-then-else构造,只需编写表单的某些内容

predicate(X) :-
  first_condition(X),
  second_condition(X).
只有当
X
的两个条件都满足时,它才会成功

如果您真的想创建一些用户界面,这就有点棘手了,因为I/O本质上是非逻辑的,特别是当涉及回溯时。我们通常调用一个程序,当它包含非逻辑结构(如I/O或cut运算符)
时,它的行为就像我们从逻辑公式中期望的那样被称为不纯

不幸的是,if-then-else构造(
->
)和否定(
\+
)是通过cut实现的,因此也是不纯的。幸运的是,大多数情况下,人们想要一个有条件的、纯粹的析取就足够了:

case(1,a).
case(2,b).
我们有一个来自Prolog执行机制的自动分支:

?- case(X,Y).
X = 1,
Y = a ;
X = 2,
Y = b.
但有时我们真的想做一些需要不纯结构的事情,比如用户输入。保持程序良好逻辑属性的最简单方法是将任务分为纯任务和非纯任务:

main :-
    uinput(Data),
    pure_predicate(Data, Result),
    write(Result).
在我们完成所有不纯部分后,
数据
与我们想要的用户数据统一起来。让我们看看
uinput/1的实现:

uinput(data(Airport,D-M-Y)) :-
    format('~nAirport? '),
    read(Airport),
    ( ground(Airport), airport(Airport, _) )
    ->
        (
            format('~nDay? '),
            read(D),
            format('~nMonth? '),
            read(M),
            format('~nYear? '),
            read(Y),
            ( ground(D-M-Y), isDate(D-M-Y) )
        ->
        true
        ;
        throw(failure('unknown date'))
        )
    ;
    throw(failure('unknown airport'))
    .
我们从输入中连续读取术语,如果无法处理,则抛出异常。为了使if-then-else结构正常工作,我们需要特别小心。如果我们比较这两个查询:

?- between(1,3,X), write(X).
1
X = 1 ;
2
X = 2 ;
3
X = 3.

您可以看到if-then-else正在丢失解决方案。这意味着我们需要确保我们的条件是确定性的。要求用户输入术语作为基础已经是一个好主意,因为没有变量,只有一个解决方案术语。尽管如此,对其中一个数据谓词
airport/1
isDate/1
的调用可能多次生成相同的术语,或者根本不终止。在这种情况下,我们只需要确保每个机场都有一个唯一的快捷方式名称,我们还可以生成日期,而不重复:

airport(nyc, 'New York City').
airport(wdc, 'Washington DC').

isDate(X-Y-Z) :-
    between(1,31,X),
    between(1,12,Y),
    between(1970,2100,Z).
实现
uinput
的另一个技巧是,当我们验证了所有内容后,我们就成功地使用
true
。现在的唯一效果是用用户输入的任何内容实例化
数据

如果我们给出了实际实现的虚拟实现,我们就可以尝试以下几种实现:

pure_predicate(_Data, Result) :-
    % here goes the actual stuff
    Result='we have found something awesome'.
在提示下,我们可以毫无困难地使用纯谓词:

?- pure_predicate(someinputdata,Y).
Y = 'we have computed something awesome'.
另一方面,我们也可以使用完整谓词,如下所示:

airport(nyc,'newyork').
?- main(_).

Airport? wdc.

Day? |: 1.

Month? |: 2.

Year? |: 2000.
we have found something awesome
true.
由于我们使用read,我们必须输入prolog术语,并以一个点结束,但一切都按预期进行

如果用户输入失败,我们得到:

?- main(_).

Airport? bla(X).

ERROR: Unhandled exception: failure('unknown airport')

请注意,我们只是经历了这个问题,实际上很早就失败了,并在这种情况下给用户一条消息。对于实际的计算,这是完全不必要的。

什么是!?。我在线阅读了文档,发现了!剪切谓词。你能详细说明一下最后一条语句吗?考虑查询是机场(NYC),也就是说,由于机场(NYC,NeYYK)在数据库中,查询应该成功。当您运行它时,Prolog将发现“nyc”确实在数据库中,并将打印“true”。但是,如果您要求Prolog提供更多解决方案(如果您在控制台中输入“;”),Prolog将尝试执行isAirport(Air)定义的另一个分支,即“write('Airport not found')、fail”部分,这不是我们想要的。正因为如此,我们使用!,这告诉Prolog停止在isAirport(Air)中搜索替代解决方案。请记住,这是非常粗略的解释我建议学习更多关于如何使用的详细教程!如果我想探索所有可能的路径,直到谓词返回false。这是我的新问题:fly(开始,结束):-fly\u helper(开始,结束);写入('未找到路径'),nl,失败。prolog将只获得一个开始、结束和终止。如果我去掉fly_helper后面的语句,它将显示所有可能的路径。我想知道,但我也想知道错误。如果你查询
机场(abc,)
,并且
abc
不是数据库中的机场,它就会失败。您不需要检查第二个参数中的变量。事实上,
Air(Air,T)
将失败,如果
Air
不是机场,您的
var(T)
甚至不会被调用。在编写完整的程序之前,Prolog有一些非常基本的行为需要学习。你应该读一本好的教科书和/或教程。