Prolog 编写一个接受包装常量的函数,但只有一级深度

Prolog 编写一个接受包装常量的函数,但只有一级深度,prolog,Prolog,我想写一个函数(很抱歉这里可能没有使用正确的术语)wubble,它对于特定的常量是正确的,如果封装到另一个常量中,对于那些常量也是正确的,但只有一层深!示例: % are supposed to be TRUE: ?- wubble(foo). ?- wubble(bar). ?- wubble(wrapper(foo)). ?- wubble(wrapper(bar)). % are suppoed to be FALSE: ?- wubble(not_in_knowledge_base).

我想写一个函数(很抱歉这里可能没有使用正确的术语)
wubble
,它对于特定的常量是正确的,如果封装到另一个常量中,对于那些常量也是正确的,但只有一层深!示例:

% are supposed to be TRUE:
?- wubble(foo).
?- wubble(bar).
?- wubble(wrapper(foo)).
?- wubble(wrapper(bar)).

% are suppoed to be FALSE:
?- wubble(not_in_knowledge_base).
?- wubble(wrapper(wrapper(foo))).
天真的(至少在我的头脑中)实现如下所示:

wubble(foo).
wubble(bar).

wubble(wrapper(wrapper(_))) :- !, fail.
wubble(wrapper(X)) :- wubble(X).
这适用于上面的查询。但是,我无法使用此实现枚举
wubble
的所有有效
X

?- wubble(X).
X = foo
X = bar

因此,缺少
X=wrapper(foo)
X=wrapper(bar)
。是否有可能以某种方式修复我的实现?

您可以将事实与规则分开:

wubble_(foo).
wubble_(bar).

wubble(X) :- wubble_(X).
wubble(wrapper(X)) :- wubble_(X).

正如OP自己所指出的,在这种特殊情况下,一个解决方案是:

wubble(foo).
wubble(bar).

wubble(wrapper(X)) :- wubble(X), ((X = wrapper(_), !, fail); true).
由于他还要求解释这种模式,以下是我的最佳选择:

给定上述知识库,类似于
wuble(X)
的查询自上而下地查找与目标
wuble(X)
相统一的事实或规则头。如果它找到了一个事实,比如
wubble(foo)
,目标就成功了,将
X
与事实的内部项统一起来,在本例中是
foo
。之后,我们可以告诉Prolog返回到最后一个选择点(Prolog在此过程中构建的深度优先搜索树中的一个节点),在本例中,它是由原始目标
wubble(X)
给出的,并让它寻找该目标的其他解决方案。如果我们在这里这样做,我们当然会得到第二个常数
wubble(bar)
的事实

现在来看有趣的部分。如果我们再次回溯,满足目标
wubble(X)
的唯一方法就是满足规则的前提条件。现在让我们机械地讨论一下。这可能令人惊讶,但是
wuble(包装器(X))
wuble(X)
相结合;你必须把这些
X
e看作是独立的。在查询
wuble(X)
和规则定义
wuble(包装器(X)):-…
的情况下,
X
只是一个本地名称。实际上,在这种情况下,这两个变量是独立的、未实例化的变量,由于未实例化的变量基本上与所有变量相统一,因此我们有
X=wrapper(X)
,因此规则的头部与我们的查询相匹配。现在,对于查询和规则,也许我们应该分别调用它们
X1
X2

现在规则的尾部是一个连词,所以我们首先尝试满足第一个目标,
wubble(X)
,它创建了一个新的选择点。现在这个过程基本上重新开始:我们从上到下搜索知识库中与之相一致的东西,首先找到
wubble(foo)
。因此,
X2
现在统一为
foo
,我们检查连接的第二部分,现在是
X2=foo
,是否成功,因为
foo\=wrapper(41;
。因此,由于连接的两个目标都是通过
X2=foo
实现的,因此我们最初的目标也是通过
X1=wrapper(X2)=wrapper(foo)
实现的

从这一点回溯,我们基本上回到了第二个选择点,由规则中连接的第一个目标创建。接下来,我们找到
X2=bar
,它再次检查连接的第二部分,我们最初的目标通过
X1=wrapper(bar)
成功

接下来,我们再回到规则上来;我们统一了
X2=wrapper(X3)
,我们的新目标是
wuble(X3)
,创建了一个新的选择点,这在
X3=foo
中获得了成功,第二部分也得到了验证。现在我们再上一层,我们有了
X2=wrapper(foo)
。这不符合连词的第二部分!它会触发
!,失败
,所以我们最初的目标是
wubble(X1)
,我们统一了
X1=wrapper(X2)=wrapper(wrapper(foo))
这次失败了。但不仅如此,我们还进行了剪切,这消除了第一个递归调用的选择点以及它下面的所有内容,因此我们甚至不再尝试
X3=bar
X3=wrapper(X4)

因此,我们进一步回到我们最初的目标选择点
wubble(X1)
;但数据库中没有与此匹配的其他子句,因此我们完成了

现在我明白了这可能很难以文本形式理解,因此我尝试将搜索树可视化:


我找到了一个解决方案:
wuble(wrapper(X)):-wuble(X),((X=wrapper()),!,fail);true)。
。但我不太明白它是怎么工作的。如果有人能写一个答案来解释我的解决方案,也许能提供一个更好的解决方案,那就太棒了。亲爱的匿名投票人,想解释一下反对票吗?:)