I want to write a predicate that an integer and a list of digits, and succeed if Digits contain the digits of the integer in the proper order, i.e:
?-digit_lists( Num, [1,2,3,4] ).
[Num == 1234].
Here is what I have so far:
my_digits( 0, [] ).
my_digits(N,[A|As]) :- N1 is floor(N/10), A is N mod 10, my_digits(N1, As).
Here comes yet another variant based on clpfd... Based on
(#=)/3
andif_//3
we define:Query using SICStus Prolog 4.3.3:
Works the other way round, too!
Note that the above is faster than
number_digits/3
as proposed by @mat in his answer.You could also avoid recursion and use in-built predicates for type conversions:
The first line converts the list to an atom, and the second line converts this atom to a number, which will give true if that number is the same as that passed in.
I don't know if there is an even more direct way to convert the list into a number (don't think so..), in which case it could be achieved in a single line.
I think this is easier:
As already suggested, consider using finite domain constraints:
This predicate can be used in all directions. Examples with either argument instantiated:
And two more general queries:
For a class assignment? What the professor is probably looking for is something like the following. A a general rule, your analysis of the problem statement should first identify the special cases (in this case, zero and negative values) and then the general case.
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:
We could try it with
clpfd
:We get this:
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:
This gives us:
But it doesn't generate:
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.
This can parse or check, or generate if the number is a non-variable:
If you try and generate with both arguments as variables you'll get a pretty unhelpful result though:
So we can try and generate by adding another special case to my_digits:
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 thatis
does not unify, but the complexity ofclp(fd)
is good proof of why that is.I hope someone else has a more elegant solution!