【问题标题】:Converting a list of Bytes to Integer in Prolog在 Prolog 中将字节列表转换为整数
【发布时间】:2017-03-17 16:04:08
【问题描述】:

我正在尝试将字节列表转换为其对应的整数。我想按照文档注释的建议绑定到第二个变量。我将其打印出来作为临时破解。

% 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

【问题讨论】:

    标签: prolog byte-shifting


    【解决方案1】:

    我想稍微扩展一下@WillemVanOnsem 的好答案。这是他发布的版本:

    字节整数(字节列表,R):- bytes_int(BytesList, 0, 0, R)。 字节整数([],_,R,R)。 字节整数([H|T],S0,R0,R):- R1 是 R0 + H

    所以,让我们尝试一些查询。一、问题中提供的测试用例:

    ?- bytes_int([42,121,56], I)。 我 = 3701034

    很好,它有效。所以让我们尝试一个更一般的情况,我查询 三个字节,但不指定它们的值:

    ?- bytes_int([A,B,C], I)。 错误:参数没有充分实例化

    不幸的是,这不起作用:使用低级整数算术排除了这种更一般的用例。此限制适用于所有更一般的查询,即使它们有时可能会产生解决方案:

    ?- bytes_int(Bs, I)。 Bs = [], 我 = 0 ; 错误:参数没有充分实例化

    至少 second 参数被完全实例化的更具体的情况如何:

    ?- bytes_int(Bs, 3701034)。 错误:参数没有充分实例化

    不,在这种情况下,谓词也不能产生任何答案。

    嗯,这一切都在意料之中,更多有命令倾向的程序员会在这一点上说。你认为我们是什么? 声明式程序员?

    是的。

    因此,我对上述版本进行了以下直接更改,以使其更具声明性:我将 (is)/2 替换为 (#=)/2。是的,我知道,40 年前的书没有这样做,但还是让我们这样做,看看我们会得到什么回报:

    字节整数(字节列表,R):- bytes_int(BytesList, 0, 0, R)。 字节整数([],_,R,R)。 字节整数([H|T],S0,R0,R):- R1 #= R0 + H

    让我们从最一般的查询开始,我们只要求任何答案

    ?- bytes_int(Bs, I). Bs = [], 我 = 0 ; Bs = [_15310], I#=_15310

    不错!所以我们现在得到了更多的答案。事实上,我们现在可以测试非终止:

    ?- bytes_int(Bs, I), false不终止

    这个查询终止的事实令人放心:由于谓词应该适用于任意长度的列表,它不能普遍终止。

    让我们再试几个案例:

    ?- bytes_int([A,B,C], I)。 _3674#=A

    上面就是这种情况:我们现在得到了所有答案的符号表示,这有时非常有用。

    特别是,原始测试用例当然自然地遵循作为更一般查询的特例

    ?- bytes_int([42,121,56], I)。 我 = 3701034。

    这和以前完全一样。

    所以还有一种情况需要测试:实例化的 second 参数怎么样?

    ?- bytes_int(Bs, 3701034). Bs = [_5164], 3701034#=_5164

    这至少会产生答案。我把它作为一个练习来改进这一点。回想一下,到目前为止,我所做的只是将(is)/2 替换为(#=)/2,仅此一项就已经大大增加了这种关系的普遍性。根据您的 Prolog 系统,您目前可能需要导入一个库才能从这个声明式整数运算中受益。

    【讨论】:

      【解决方案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([], _, <b>R, R</b>).

      在另一种情况下,我们只需更新累积和,更新移位大小,并在列表的 tail 上执行递归:

      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.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-17
        • 2015-12-06
        • 1970-01-01
        • 1970-01-01
        • 2013-09-27
        • 1970-01-01
        相关资源
        最近更新 更多