我想扩展一下@WillemVanOnsem的好回答。这里是他发布的版本:
bytes_int(BytesList, R) :-
bytes_int(BytesList, 0, 0, R).
bytes_int([], _, R, R).
bytes_int([H|T], S0, R0, R) :-
R1 is R0 + H << S0,
S1 is S0 + 8,
bytes_int(T, S1, R1, R).
因此,让我们尝试几个查询。首先,测试案例中的问题提供:
?- bytes_int([42,121,56], I).
I = 3701034.
尼斯,它的工作原理。因此,让我们尝试一种更普遍的情况,在那里我查询有关三个字节,但不指定它们的值:
?- bytes_int([A,B,C], I).
ERROR: Arguments are not sufficiently instantiated
不幸的是,这并不工作:使用低级别的整数运算,而消除这种更一般用例。这种限制延续到所有尚未更普遍的疑问,尽管他们有时会产生一个解决方案:
?- bytes_int(Bs, I).
Bs = [],
I = 0 ;
ERROR: Arguments are not sufficiently instantiated
什么更具体的情况,其中,至少秒参数完全实例:
?- bytes_int(Bs, 3701034).
ERROR: Arguments are not sufficiently instantiated
不,这个谓词在这种情况下也不能产生任何答案。
那么,这一切都是可以预料的,更迫切的倾向程序员会在这一点上说。你觉得我们是什么? 声明式程序员?
是的。
因此,为了使其更具说明性,我对以上版本进行了以下直接更改:我将(is)/2
替换为(#=)/2
。是的,我知道,从40 年以前的书都没有做到这一点,但还是让我们做 一下,看看我们得到的回报:
bytes_int(BytesList, R) :-
bytes_int(BytesList, 0, 0, R).
bytes_int([], _, R, R).
bytes_int([H|T], S0, R0, R) :-
R1 #= R0 + H << S0,
S1 #= S0 + 8,
bytes_int(T, S1, R1, R).
让我们先从最一般的查询,这里马上我们只是要求任何回答任何:
?- bytes_int(Bs, I).
Bs = [],
I = 0 ;
Bs = [_15310],
I#=_15310<<0 ;
Bs = [_16050, _16056],
_16086#=_16050<<0,
_16086+_16118#=I,
_16118#=_16056<<8 .
不错!所以我们现在得到更多的答案。其实,我们现在可以测试 nontermination:
?- bytes_int(Bs, I), false.
nontermination
这个查询不终止事实是令人放心的:由于谓语应该保持任意长度的列表,它必须 没有普遍终止。
让我们尝试了几个案例:
?- bytes_int([A,B,C], I).
_3674#=A<<0,
_3674+_3706#=_3700,
_3706#=B<<8,
_3700+_3754#=I,
_3754#=C<<16.
这是从上面的情况:我们现在得到所有的答案,这有时是相当有用的符号表示。
特别,当然原有的测试情况如下自然地一个特例更多的一般查询:
?- bytes_int([42,121,56], I).
I = 3701034.
这像以前一样工作的。
所以还有一种情况需要测试:第二个参数被实例化了么?
?- bytes_int(Bs, 3701034).
Bs = [_5164],
3701034#=_5164<<0 ;
Bs = [_6056, _6062],
_6080#=_6056<<0,
_6080+_6112#=3701034,
_6112#=_6062<<8 .
这至少会得到答案。我把它作为一个练习来改进。回想一下,到目前为止,我所做的只是将(is)/2
替换为(#=)/2
,而这一点已经显着增加了这种关系的普遍性。根据您的Prolog系统,您现在可能需要导入一个库,以便从此声明式整数算术中受益。