I don't agree with @ssBarBee. After all, you should get 4321 if you supply your list and their allegation is correct; but instead you get this:
?- my_digits(Num, [1,2,3,4]).
ERROR: is/2: Arguments are not sufficiently instantiated
We could try it with clpfd
:
my_digits( 0, [] ).
my_digits(N,[A|As]) :- N1 #= N/10, A #= N mod 10, my_digits(N1, As).
We get this:
?- my_digits(Num, [1,2,3,4]), label([Num]).
Num = -6789 ;
Num = 4321.
I find all that pretty curious, but tracing with clpfd is not pleasant.
If you just wanted to parse a list of numbers I would be inclined to make it tail recursive like so:
my_digits(Num, List) :- my_digits(0, List, Num).
my_digits(Num, [], Num).
my_digits(N, [A|As], Num) :- N1 is N * 10 + A, my_digits(N1, As, Num).
This gives us:
?- my_digits(Num, [1,2,3,4]).
Num = 1234 ;
false.
But it doesn't generate:
?- my_digits(1234, X).
ERROR: is/2: Arguments are not sufficiently instantiated
If I were solving this without clpfd, I'd be inclined at this point to just inspect my arguments and have separate predicates. Gross, I know, but that's what I'd do.
my_digits(Num, List) :-
nonvar(List),
my_digits_p(0, List, Num).
my_digits(Num, List) :-
var(List),
my_digits_g(Num, ListRev),
reverse(ListRev, List).
my_digits_p(Num, [], Num).
my_digits_p(N, [A|As], Num) :- N1 is N * 10 + A, my_digits(N1, As, Num).
my_digits_g(0, []) :- !.
my_digits_g(N, [A|As]) :- A is N mod 10, N1 is floor(N / 10), my_digits_g(N1, As).
This can parse or check, or generate if the number is a non-variable:
?- my_digits(1234, X).
X = [1, 2, 3, 4].
?- my_digits(X, [1,2,3,4]).
X = 1234 ;
false.
?- my_digits(1234, [1,2,3,4]).
true;
false.
If you try and generate with both arguments as variables you'll get a pretty unhelpful result though:
?- my_digits(X, Y).
X = 0,
Y = [].
So we can try and generate by adding another special case to my_digits:
my_digits(Num, List) :-
var(Num), var(List),
my_digits_g_from(0, Num, ListRev),
reverse(ListRev, List).
my_digits(Num, List) :-
nonvar(List),
my_digits_p(0, List, Num).
my_digits(Num, List) :-
var(List),
my_digits_g(Num, ListRev),
reverse(ListRev, List).
my_digits_g_from(N, N, List) :- my_digits_g(N, List).
my_digits_g_from(N, Num, List) :- succ(N, N1), my_digits_g_from(N1, Num, List).
That's a lot of code, and a good demonstration of the kind of acrobatics one has to do when not using clp(fd)
. It's an unfortunate fact that when doing arithmetic in Prolog one must work around the fact that is
does not unify, but the complexity of clp(fd)
is good proof of why that is.
I hope someone else has a more elegant solution!