定义一个包含数字及其否定的谓词并枚举它们
我需要定义一个plusminus(X).包含 2 个数字的谓词,s(0) 是 0 的后继,表示 s(s(s(0))) = 3 和它们的负数 p(0) 表示 -1 表示 p(p (p(0))) = -3 并且可以枚举为:
? plusminus(X).
X = 0 ? ;
X = s(0) ? ;
X = p(0) ? ;
X = s(s(0)) ? ;
X = p(p(0)) ? ;
X = s(s(s(0))) ? ;
X = p(p(p(0))) ? ;
...
我有以下解决方案,但我没有按照我想要的顺序得到它,
negative(0, 0).
negative(s(X), p(Y)) :- negative(X, Y).
plusminus(X) :- negative(X, _).
如何更改以下内容以获得我想要的输出?
回答
这个答案有点大,但它展示了一个关于公平枚举答案的更一般的观点:如果你为你的对象定义了一个“大小”度量,你可以通过增加大小来强制枚举。
首先,数字的定义,它要么是 0,要么是正数或负数:
numeral(0).
numeral(X) :-
positive(X).
numeral(X) :-
negative(X).
positive(s(0)).
positive(s(X)) :-
positive(X).
negative(p(0)).
negative(p(X)) :-
negative(X).
例子:
?- numeral(N).
N = 0 ;
N = s(0) ;
N = s(s(0)) ;
N = s(s(s(0))) .
我们可以看到这是不公平的:它不会产生负数。但是,它确实接受它们:
?- numeral(p(p(p(0)))).
true ;
false.
在这种特殊情况下,我们可以强制枚举负数(仅):
?- Negative = p(_), numeral(Negative).
Negative = p(0) ;
Negative = p(p(0)) ;
Negative = p(p(p(0))) ;
Negative = p(p(p(p(0)))) .
与其他答案不同,这不接受带有混合构造函数符号的数字:
?- numeral(p(s(p(0)))).
false.
现在来衡量“尺寸”。这基本上只是一个数字的绝对值。我们分别为正负数定义它,和以前一样:
numeral_size(0, 0).
numeral_size(Positive, Size) :-
positive_size(Positive, Size).
numeral_size(Negative, Size) :-
negative_size(Negative, Size).
positive_size(s(0), s(0)).
positive_size(s(X), s(Size)) :-
positive_size(X, Size).
negative_size(p(0), s(0)).
negative_size(p(X), s(Size)) :-
negative_size(X, Size).
(请注意,这与 的定义相同numeral/1,只是到处都有一个额外的大小参数。)
现在plusminus/1可以首先枚举(非负)数字 0、1、2、3 等,作为每个预期答案的大小。然后它枚举具有这些大小的数字;这将强制所需的整体枚举顺序为 0, 1, -1, 2, -2, ...
plusminus(X) :-
numeral(Size),
numeral_size(X, Size).
例子:
?- plusminus(X).
X = 0 ;
X = s(0) ;
X = p(0) ;
X = s(s(0)) ;
X = p(p(0)) ;
X = s(s(s(0))) ;
X = p(p(p(0))) ;
X = s(s(s(s(0)))) ;
X = p(p(p(p(0)))) .
这是一个非常通用的模式:例如,如果您有一个描述列表的谓词,并且您想通过增加大小来公平地枚举它们,请length(List, _N)在它前面放置一个目标。这是“大小”谓词,它将强制按大小 0、1、2 等枚举列表。