2017-03-17 42 views
1

我试图将字节列表转换为相应的整数。我想绑定到第二个变量,因为记录意见会提示。我将它打印为临时黑客。在Prolog中将字节列表转换为整数

% bytes_int(+ByteList, -IntegerRepresentation) 
% converts a list of bytes to integer representation 
% I accounts for bitshifting 
bytes_int(BytesList, _) :- 
    bytes_int(BytesList, 0, 0). 

bytes_int([], _, Num) :- 
    format('~w', Num). 
bytes_int([B|Bs], I, Num) :- 
    B0 is B << I, 
    Num0 is B0 + Num, 
    I0 is I + 8, 
    bytes_int(Bs, I0, Num0). 

这是打印正确的值,但我不知道为什么它没有绑定到第二个变量进一步使用。我能做些什么来实现这一点?

?- bytes_int([42, 121, 56], N). 
3701034 

回答

2

时出现的第一个问题是在这里:

bytes_int(BytesList, _) :- 
    bytes_int(BytesList, 0, 0). 

不结果(_)与呼叫可变绑定。你可能想使用:

bytes_int(BytesList, R) :- 
    bytes_int(BytesList, 0, R). 

下一页你不使用蓄电池。这里的累加器可以存储您迄今为止获得的累计金额。所以我们声明一个额外的参数:

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(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], N). 
N = 3701034. 
3

我想扩展一下@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系统,您现在可能需要导入一个库,以便从此声明式整数算术中受益。