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.