1

I wrote a Prolog predicate which transforms a list of digits in a number. So, for example, if the input is the list [1, 2, 3] then the output will be the number 123. This is my code:

convertListToNum([], Col, Col).

convertListToNum([H|T], Col, R):-
    Col2 is Col * 10 + H,
    convertListToNum(T, Col2, R).

convertListToNumMain(L, R):-
    convertListToNum(L, 0, R).

As you can see, the arguments of the predicate are L=input, R=output, since I provide the list L as input into ConvertListToNumMain and I will get as output the number in R. If I try this predicate, it works as expected: convertListToNumMain([1, 2, 3], R) will give as output R=123.

Now what I want to do is use this function by providing the output number instead of the input list. I will use L=output, R=input. So I will not provide the list L anymore, I will provide the number R and expect to receive the list as output. So what I want is to call this: convertListToNumMain(L, 123) and I expect to receive as output L=[1, 2, 3]. However, when I call this I get the error Arguments are not sufficiently instantiated. I assume it is because in the line Col2 is Col * 10 + H I try to work with the first element of the list even tough the list is not instantiated, but I am not sure. What can I do to make this work?

I want to convert a list of digits to a number and then the number back to a list of digits and I thought I could get away with this, but apparently not. The alternative is to create another complex and inefficient predicate which will at each step find the most significant digit of a number, then add it to the list, find that number without that most significant digit and then make the next call. Or at least that is my idea. That is a lot of code and (it seems to me) more inefficient. So is there any way I can use what I already have by providing the output? If not, is there a better way than my idea above to convert a number into a list of digits (recursively, of course, since I'm using Prolog)?

false
  • 10,264
  • 13
  • 101
  • 209
abc xyz
  • 119
  • 1
  • 9

1 Answers1

3

It's not that complicated. Or inefficient.

int_list( N , Ds ) :- nonvar(N), number_to_digits(N,Ds).
int_list( N , Ds ) :- nonvar(Ds), digits_to_number(Ds,0,N).

digits_to_number( [] , N , N ) .
digits_to_number( [D|Ds] , T , N ) :-
  T1 is 10 * T + D ,
  digits_to_number(Ds,T1,N).

number_to_digits( 0 , [0] ).
number_to_digits( N , Ds  ) :-
  N > 0,
  digits(N, [], Ds).

digits( N , T  , Ds ) :-
  N > 0,
  D  is N mod 10,
  N1 is N div 10,
  digits(N1,[D|T],Ds).
digits( 0 , Ds , Ds ) .

But it might be easier to use built-in predicate number_codes/2:

int_digits( N , Ds ) :- nonvar(Ds) , codes_digits(Cs,Ds) , number_codes(N,Cs)  .
int_digits( N , Ds ) :- nonvar(N)  , number_codes(N,Cs)  , codes_digits(Cs,Ds) .

codes_digits( []     , []     ) .
codes_digits( [C|Cs] , [D|Ds] ) :- code_digit(C,D), codes_digits(Cs,Ds).

code_digit(C,D) :- nonvar(C), D is C-48.
code_digit(C,D) :- nonvar(D), C is D+48.                                                      

Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135