如何在序言中编写数字分类器?
How to write number classifiers in prolog?
第一次玩 Prolog,虽然我认为我知道它基本上有什么用,但我发现很难用它完成任何事情。所以,我试图找到最简单的任务,但我什至没能完成。
我认为这是因为我不知道 prolog 数据类型(数字)应该如何工作或者它们有特殊的语法。
所以,我对偶数进行分类的第一次尝试是:
even(0).
even(X) :- even(X-2).
结果:查询的堆栈溢出:even(2)。
所以我想如果不是这样,那么也许是:
even(0).
even(X+2) :- even(X).
even(2) 的结果:false。
所以我的简单问题是:如何在序言中编写这么简单的东西?是不是因为我用了数字,所以一切都不起作用?
使用is/2
强制算术求值。就其本身而言,Prolog 术语只是结构符号实体,X-2
是 arity 2 的复合术语,-(X,2)
:
3 ?- write_canonical( X-2 ).
-(_,2)
true.
但是is
用于算术表达式:
4 ?- Z is 5-2.
Z = 3.
因此您的定义应该是
even(X):- X=:=0 -> true
; X > 0 -> Y is X-2, even(Y).
这种定义的缺点是不能以生成的方式调用它,例如even(X)
一个接一个地生成所有偶数。
它只适用于检查给定的数字。为简单起见,它会忽略负数并始终失败。
为什么不按正常方式进行:
is_even(X) :-
X /\ 0x1 =:= 0.
如果你想在回溯时枚举非负偶数当参数未绑定时,这完全是另一回事。这可能很容易说:
even(X) :-
between(0, infinite, X),
is_even(X).
您可以像这样使用第二个定义:
?- even(X).
X = 0 ;
X = 2 ;
X = 4 ;
X = 6 . % and so on
is_even/1
和even/1
有一些区别:
is_even/1
适用于任何正整数或负整数
令人惊讶的是,is_even/1
也适用于计算结果为整数的表达式,例如 X = 3, ..., is_even(X + 1)
。这是因为 =:=
接受两边的算术表达式。
even/1
使用 between/3
,因此 X 的域和错误条件与 between/3
的第三个参数相同。
- 因此,
even/1
不适用于负整数或算术表达式。
等等,还有更多!
显然,between(0, infinite, X)
不是您可以在除 SWI 之外的几乎所有 Prolog 中执行的操作。因此,您可以使用另一个谓词来枚举正整数(列表长度):
even_f(X) :-
length(_, X),
is_even(X).
(为此感谢@false)
第一次玩 Prolog,虽然我认为我知道它基本上有什么用,但我发现很难用它完成任何事情。所以,我试图找到最简单的任务,但我什至没能完成。
我认为这是因为我不知道 prolog 数据类型(数字)应该如何工作或者它们有特殊的语法。
所以,我对偶数进行分类的第一次尝试是:
even(0).
even(X) :- even(X-2).
结果:查询的堆栈溢出:even(2)。
所以我想如果不是这样,那么也许是:
even(0).
even(X+2) :- even(X).
even(2) 的结果:false。
所以我的简单问题是:如何在序言中编写这么简单的东西?是不是因为我用了数字,所以一切都不起作用?
使用is/2
强制算术求值。就其本身而言,Prolog 术语只是结构符号实体,X-2
是 arity 2 的复合术语,-(X,2)
:
3 ?- write_canonical( X-2 ).
-(_,2)
true.
但是is
用于算术表达式:
4 ?- Z is 5-2.
Z = 3.
因此您的定义应该是
even(X):- X=:=0 -> true
; X > 0 -> Y is X-2, even(Y).
这种定义的缺点是不能以生成的方式调用它,例如even(X)
一个接一个地生成所有偶数。
它只适用于检查给定的数字。为简单起见,它会忽略负数并始终失败。
为什么不按正常方式进行:
is_even(X) :-
X /\ 0x1 =:= 0.
如果你想在回溯时枚举非负偶数当参数未绑定时,这完全是另一回事。这可能很容易说:
even(X) :-
between(0, infinite, X),
is_even(X).
您可以像这样使用第二个定义:
?- even(X).
X = 0 ;
X = 2 ;
X = 4 ;
X = 6 . % and so on
is_even/1
和even/1
有一些区别:
is_even/1
适用于任何正整数或负整数
令人惊讶的是,is_even/1
也适用于计算结果为整数的表达式,例如X = 3, ..., is_even(X + 1)
。这是因为=:=
接受两边的算术表达式。even/1
使用between/3
,因此 X 的域和错误条件与between/3
的第三个参数相同。- 因此,
even/1
不适用于负整数或算术表达式。
等等,还有更多!
显然,between(0, infinite, X)
不是您可以在除 SWI 之外的几乎所有 Prolog 中执行的操作。因此,您可以使用另一个谓词来枚举正整数(列表长度):
even_f(X) :-
length(_, X),
is_even(X).
(为此感谢@false)