Prolog:判断给定整数是否为 2 的幂并且可用作生成器的谓词

Prolog: Predicate that tells if given integer is a power of two and is usable as a generator

我想要一个谓词 isPowTwo/1,它对 2 的每一次幂都成立。这是我的方法:

isPowTwo(N) :- N > 0, N is N /\ (-N).

它工作得很好,如果我给它整数:

?- isPowTwo(2).
true.

?- isPowTwo(4).
true.

?- isPowTwo(6).
false.

但是当我想要它作为发电机使用时它不起作用:

?- isPowTwo(N).
ERROR: >/2: Arguments are not sufficiently instantiated

我如何编写一个谓词,以升序生成 2 的幂?

编辑:重要的是使用普通整数而不是 Peano 数。

经验法则

Are you reasoning over integers? → Use your Prolog system's CLP(FD) constraints.

示例解决方案

power_of_two(N) :-
    N #> 0,
    N #= 2^_.

示例查询和答案

具体整数

?- power_of_two(2).
true.

?- power_of_two(4).
true.

?- power_of_two(6).
false.

最一般的查询

?- power_of_two(N).
N in 1..sup,
2^_G844#=N.

枚举

?- power_of_two(N), length(_, N).
N = 1 ;
N = 2 ;
N = 4 ;
N = 8 ;
N = 16 ;
N = 32 ;
etc.

结论

使用正常 整数,不使用 Peano 数。

约束允许我们以纯粹、一般和简洁的方式陈述解决方案。

我发现另一种方法作为生成器效果很好(比使用 length(_, N) 作为目标的 CLP(FD) 版本更快),不使用 clpfd,但往往以无限结束-loop 如果用作验证者:

isPowTwo(1).
isPowTwo(N) :- isPowTwo(N1), N is N1 * 2.

查看其行为:

?- isPowTwo(N).
N = 1 ;
N = 2 ;
N = 4 ;
N = 8 ;
N = 16 ;
N = 32 ;
N = 64 ;
N = 128 ;
N = 256 ;
N = 512 ;
N = 1024 ;
...

?- isPowTwo(4).
true ;
... (infinite loop)

?- isPowTwo(3).
... (infinite loop)