Search code examples
prologbyte-shifting

Converting a list of Bytes to Integer in Prolog


I'm trying to convert a list of bytes to it's corresponding integer. I would like to bind to the second variable as the documenting comment would suggest. I'm printing it out as a temporary hack.

% 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).

It's printing the correct value, but I'm not sure why it's not binding to the second variable for further use. What improvements can I do to accomplish this?

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

Solution

  • A first problem that occurs is here:

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

    You do not bind the result (_) with a variable in the call. You probably want to use:

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

    Next you do not use an accumulator. The accumulator here can store the cumulative sum you have obtained this far. So we declare an additional parameter:

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

    Now we are set for the real algorithm. In case we reached the end of the list. The thus far cumulative sum, is the final result so:

    bytes_int([], _, R, R).

    In the other case, we simply update the cumulative sum, update the shift size, and perform recursion on the tail of the list:

    bytes_int([H|T], S0, R0, R) :-
        R1 is R0 + H << S0,
        S1 is S0 + 8,
        bytes_int(T, S1, R1, R).

    And now putting it all together:

    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).
    

    This generates:

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