我在堆栈上找到了这个:reversible "binary to number" predicate
但我不明白
:- use_module(library(clpfd)).
binary_number(Bs0, N) :-
reverse(Bs0, Bs),
binary_number(Bs, 0, 0, N).
binary_number([], _, N, N).
binary_number([B|Bs], I0, N0, N) :-
B in 0..1,
N1 #= N0 + (2^I0)*B,
I1 #= I0 + 1,
binary_number(Bs, I1, N1, N).
示例查询:
?- binary_number([1,0,1], N).
N = 5.
?- binary_number(Bs, 5).
Bs = [1, 0, 1] .
有人可以解释一下代码
特别是:binary_number([], _, N, N).
(_)
库(clpfd)的作用是什么?
为什么reverse(Bs0, Bs)
?我拿走它仍然可以正常工作......
答案 0 :(得分:1)
在原作binary_number([], _, N, N).
中,_
表示您并不关心变量的值。如果您使用binary_number([], X, N, N).
(不关心X
是什么),Prolog会发出单例变量警告。此外,这个谓词子句所说的是当第一个参数是[]
(空列表)时,第3和第4个参数是统一的。
正如评论中所解释的那样,use_module(library(clpfd))
导致Prolog使用该库进行有限域上的约束逻辑编程。您还可以通过谷歌搜索" prolog clpfd"来找到很多有关它的信息。
通常,在Prolog中,比较的算术表达式要求表达式完全实例化:
X + Y =:= Z + 2. % Requires X, Y, and Z to be instantiated
Prolog会评估并进行比较并产生真假。如果没有实例化任何这些变量,它将抛出错误。同样,对于赋值,is/2
谓词要求右侧表达式可以完全计算所有实例化的特定变量:
Z is X + Y. % Requires X and Y to be instantiated
使用CLPFD,你可以让Prolog"探索"解决方案给你。您还可以进一步指定要将变量限制为的域。因此,您可以说X + Y #= Z + 2
和Prolog可以在X
,Y
和Z
中枚举可能的解决方案。
顺便说一下,原始实现可以稍微重构一次,以避免每次取幂,并消除reverse
:
:- use_module(library(clpfd)).
binary_number(Bin, N) :-
binary_number(Bin, 0, N).
binary_number([], N, N).
binary_number([Bit|Bits], Acc, N) :-
Bit in 0..1,
Acc1 #= Acc*2 + Bit,
binary_number(Bits, Acc1, N).
这适用于以下查询:
| ?- binary_number([1,0,1,0], N).
N = 10 ? ;
no
| ?- binary_number(B, 10).
B = [1,0,1,0] ? ;
B = [0,1,0,1,0] ? ;
B = [0,0,1,0,1,0] ? ;
...
但正如评论中所指出的那样,对于诸如Bs = [1|_], N #=< 5, binary_number(Bs, N).
A solution was presented by @false等仅仅修改上述内容的案例有助于解决这些终止问题。为方便起见,我在此重申这一解决方案:
:- use_module(library(clpfd)).
binary_number(Bits, N) :-
binary_number_min(Bits, 0,N, N).
binary_number_min([], N,N, _M).
binary_number_min([Bit|Bits], N0,N, M) :-
Bit in 0..1,
N1 #= N0*2 + Bit,
M #>= N1,
binary_number_min(Bits, N1,N, M).