binaryintegerprologswi-prolog

Binary to Integer in Prolog


Ok so. Still learning the basics in prolog and was given the bonus question on an assignment of converting a binary number into an integer based on the following definition for a binary num:

bin(bin(X),bin(Y,Z)):-
    bin(X),
    bin(Y,Z).
bin(bin(X),bin(Y)):-
    bin(X),
    bin(Y).
bin(zero).
bin(one).
% So for example, 10010 becomes:
% bin(bin(one),bin(bin(zero),bin(bin(zero),bin(bin(one),bin(zero)))))

Now I'll admit, I haven't haven't even begun to approach this one. It feels very daunting given my limited understanding of the language, and so I've only got the current base cases:

bin_int(bin(zero),0).
bin_int(bin(one),1).
bin_int(bin(B),X):-bin_int(B,X).

Like I said, limited understanding.
It's obviously gonna be recursive but I'm absolutely on how to go about it.
I'll post updates as work on it but for now it's just pseudocode so bear with me.

So, until B is 'one' or 'zero' it is going to have to be two bins and I'm already stuck.
Like how do I write that B must be a bin() tuple and how do I handle the second bin in the tuple having a tuple in itself or not?
Anybody got any as to how to go about this one I'd greatly appreciate some help. Thanks!


Solution

  • There are two types of bin data given in the exercise: One type is something like bin(D) representing a single digit, the other is bin(D, Rest) representing a sequence of a digit followed by a rest (another digit or sequence).

    Here's the code renamed and rearranged:

    digit(zero).
    digit(one).
    
    sequence(digit(X),digit(Y)):-
        digit(X),
        digit(Y).
    sequence(digit(X),sequence(Y,Z)):-
        digit(X),
        sequence(Y,Z).
        
    binary(digit(Binary)) :-
        digit(Binary).
    binary(sequence(A, B)) :-
        sequence(A, B).
    

    Isn't this much clearer already? Thanks to the slightly rearranged code (non-recursive rules before recursive ones), we can ask Prolog to enumerate some solutions for us to explore how this behaves:

    ?- binary(B).
    B = digit(zero) ;
    B = digit(one) ;
    B = sequence(digit(zero), digit(zero)) ;
    B = sequence(digit(zero), digit(one)) ;
    B = sequence(digit(one), digit(zero)) ;
    B = sequence(digit(one), digit(one)) ;
    B = sequence(digit(zero), sequence(digit(zero), digit(zero))) ;
    B = sequence(digit(zero), sequence(digit(zero), digit(one))) ;
    B = sequence(digit(zero), sequence(digit(one), digit(zero))) ;
    B = sequence(digit(zero), sequence(digit(one), digit(one))) ;
    B = sequence(digit(zero), sequence(digit(zero), sequence(digit(zero), digit(zero)))) ;
    B = sequence(digit(zero), sequence(digit(zero), sequence(digit(zero), digit(one)))) ;
    B = sequence(digit(zero), sequence(digit(zero), sequence(digit(one), digit(zero)))) .   % etc.
    

    Note that the enumeration isn't fair: Nested sequences with a leading digit(one) will never be enumerated.

    Now for your questions:

    Like how do I write that B must be a bin() tuple

    Exactly like you did. In Prolog, you describe what is true. Everything you don't describe is not true. You do not need to describe what is not true. If you define a predicate like

    binary_integer(digit(zero), 0).
    binary_integer(digit(one), 1).
    binary_integer(sequence(Digit, Rest), ...) :- ...
    

    then any call where the first argument is not unifiable with digit(X) or sequence(X, Y) will fail. You do not need to do anything special for non-binary cases.

    and how do I handle the second bin in the tuple having a tuple in itself or not?

    Recursively. If you have a recursive rule to handle sequence(Digit, Rest), and the Rest is itself a sequence(Digit2, Rest2), then it will be handled.

    Basically you want to write (in addition to the two rules for digits zero and one) a rule like:

    binary_integer(sequence(Digit, Rest), N) :-
        "Length is the number of binary digits in Rest",
        Base is Digit << Length,
        binary_integer(Rest, RestValue),
        N is Base + RestValue.
    

    The "Length is the number of binary digits in Rest" is left as an exercise.