我有一个逻辑问题要解决,所以我想:“我知道,我会尝试Prolog!”
不幸的是,我几乎立即撞到了一堵砖墙。所涉及的假设之一是析取事实; A、B 或 C 是真的(或不止一个),但我不知道哪个是真的。从那以后,我了解到这是 something Prolog does not support 。
有很多文档似乎解决了这个问题,但其中大部分似乎立即涉及更复杂的概念并解决了更高级的问题。我正在寻找的是一种独立的方式来模拟定义上述事实(因为 Prolog 的限制,无法立即定义它)。
我怎么能解决这个问题?我可以以某种方式将它包装在规则中吗?
编辑: 我意识到我还不是很清楚。鉴于我对 Prolog 不熟悉,我不想在试图传达问题时陷入语法错误,而是使用自然语言。我想这行不通,所以无论如何我都会在伪 Prolog 中试一试。
直觉上,我想做的是这样的事情,声明 foo(a)
、 foo(b)
或 foo(c)
成立,但我不知道哪个:
foo(a); foo(b); foo(c).
然后我希望得到以下结果:
?- foo(a); foo(b); foo(c).
true
不幸的是,我试图声明的事实(即
foo(x)
至少对一个 x \in {a, b, c}
成立)不能这样定义。具体来说,它导致 No permission to modify static procedure '(;)/2'
。旁注:在声明析取事实后,从逻辑的角度来看,
?- foo(a).
的结果对我来说有点不清楚;它显然不是 true
,但 false
也没有涵盖它——在这种情况下,Prolog 根本没有足够的信息来回答该查询。编辑 2: 这里有更多的上下文,使它更像是一个真实世界的场景,因为我可能在翻译中过度简化和丢失了细节。
假设有三个人参与。爱丽丝、鲍勃和查理。 Bob 持有
{1, 2, 3, 4}
集合中的两张牌。爱丽丝向他提问,作为回应,他给她看了一张查理没有看到的卡片,或者没有给她看卡片。如果有更多卡片适用,Bob 只显示其中的一张。查理的任务是了解鲍勃拿着什么牌。正如人们所料,查理是一个自动化系统。爱丽丝问鲍勃“你有 1 还是 2?”,鲍勃向爱丽丝展示了一张卡片作为回应。 Charlie 现在得知 Bob 拥有 1 或 2。
然后爱丽丝问“你有一张 2 还是一张 3”,鲍勃没有牌可看。显然,鲍勃有一个 1,他之前给爱丽丝展示过。基于这两个事实,查理现在应该能够得出这一点。
我试图模拟的是 Bob 拥有 1 或 2 (
own(Bob, 1) \/ own(Bob, 2)
),而 Bob 不拥有 2 或 3 ( not (own(Bob, 2) \/ own(Bob, 3))
) 的知识。查询 Bob 是否拥有 1 现在应该是 true
;查理可以得出这一点。 最佳答案
对您的问题 的直接回答:
如果您可以通过有限域上的约束逻辑编程对您的问题进行建模,那么可以使用 #\
实现“异或”,如下所示:
D = 1..3, X in D #\ Y in D #\ Z in D
为了概括这一点,你可以写:disj(D, V, V in D #\ Rest, Rest).
vars_domain_disj([V|Vs], D, Disj) :-
foldl(disj(D), Vs, Disj, V in D #\ Disj).
并将其用作:?- vars_domain_disj([X,Y,Z], 2 \/ 4 \/ 42, D).
D = (Y in 2\/4\/42#\ (Z in 2\/4\/42#\ (X in 2\/4\/42#\D))).
如果您不使用 CLP(FD),例如您找不到问题和整数之间的良好映射,您可以做其他事情。假设你的变量在一个列表 List
中,其中任何一个,但只有一个,可以是 foo
,其余的不能是 foo
,你可以说:?- select(foo, [A,B,C], Rest), maplist(dif(foo), Rest).
A = foo,
Rest = [B, C],
dif(B, foo),
dif(C, foo) ;
B = foo,
Rest = [A, C],
dif(A, foo),
dif(C, foo) ;
C = foo,
Rest = [A, B],
dif(A, foo),
dif(B, foo) ;
false.
查询内容为:在列表 [A,B,C]
中,变量之一可以是 foo
,其余的必须与 foo
不同。您可以看到该查询的三种可能解决方案。原答案
可悲的是,人们经常声称 Prolog 不支持这样或那样的东西。通常,这不是真的。
您的问题目前尚不完全清楚,但请说您的意思是,使用此程序:
foo(a).
foo(b).
foo(c).
您会得到以下查询答案:?- foo(X).
X = a ;
X = b ;
X = c.
您可能将其解释为:但是,如果我理解您的问题,您需要一个规则,例如:
但是,根据上下文,它,程序的其余部分和查询,原始解决方案可能就是这个意思!
但是您确实需要在您的问题中更加具体,因为解决方案将取决于它。
编辑问题后编辑
这是在 SWI-Prolog 中可用的具有伟大
library(clpfd)
by Markus Triska 的有限域上使用约束编程的特定问题的解决方案。这是完整的代码:
:- use_module(library(clpfd)).
cards(Domain, Holds, QAs) :-
all_distinct(Holds),
Holds ins Domain,
maplist(qa_constraint(Holds), QAs).
qa_constraint(Vs, D-no) :-
maplist(not_in(D), Vs).
qa_constraint([V|Vs], D-yes) :-
foldl(disj(D), Vs, Disj, V in D #\ Disj).
not_in(D, V) :- #\ V in D.
disj(D, V, V in D #\ Rest, Rest).
以及两个示例查询:?- cards(1..4, [X,Y], [1 \/ 2 - yes, 2 \/ 3 - no]), X #= 1.
X = 1,
Y = 4 ;
false.
答案是:
或者:
?- cards(1..4, [X,Y], [1 \/ 2 - yes, 2 \/ 3 - no]), X #= 3.
false.
这是什么意思呢?
:- use_module(library(clpfd)).
使库可用。cards(Domain, Holds, QAs) :-
all_distinct(Holds),
Holds ins Domain,
maplist(qa_constraint(Holds), QAs).
这定义了我们可以从顶层查询的规则。第一个参数必须是一个有效的域:在你的情况下,它将是 1..4
表明卡片在集合 {1,2,3,4} 中。第二个参数是一个变量列表,每个变量代表 Bob 持有的一张牌。最后是一个“问题”和“答案”列表,每个都是 Domain-Answer
格式,所以 1\/2-yes
的意思是“对于这个问题,你持有 1 还是 2,答案是‘是’”。然后,我们说 Bob 持有的所有卡片都是不同的,并且每张卡片都是集合中的一张,然后我们将每个问答对映射到卡片上。
qa_constraint(Vs, D-no) :-
maplist(not_in(D), Vs).
qa_constraint([V|Vs], D-yes) :-
foldl(disj(D), Vs, Disj, V in D #\ Disj).
“否”的答案很简单:只需说对于 Bob 持有的每张牌,在提供的域中是 而不是 : #\ V in D
。not_in(D, V) :- #\ V in D.
"is"的答案意味着我们需要一个独占或 Bob 持有的所有牌; 2\/3-yes
应该导致“第一张牌是 2 或 3,或者第二张牌是 2 或 3, 但不能同时是 !”disj(D, V, V in D #\ Rest, Rest).
要理解最后一个,请尝试:?- foldl(disj(2\/3), [A,B], Rest, C in 2\/3 #\ Rest).
Rest = (A in 2\/3#\ (B in 2\/3#\ (C in 2\/3#\Rest))).
关于Prolog:模拟析取事实,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32452350/