Prolog : Comparing numbers in a list - list

I have this block of numbers:
num(1).
num(-2).
num(5).
num(50).
num(-3).
num(87).
I'm supposed to make a function that given a number it is supposed to check if that number is the smallest of that "list" of numbers given above.
ex:
not_smallest(5).
true.
not_smallest(X).
X = 1 ;
X = -2 ;
X = 5 ;
X = 50 ;
X = 87.
What i thought was making a list with the above block of numbers , and comparing a given number to all elements of the list.
But whenever i try to load the .pl doc i get this error:
Syntax error: Operator expected
what i have done so far is this:
%increments the index of a List
incr(X, X1) :-
X1 is X + 1.
%L-list containing "list" of numbers, N - elements of that "list",
I-index , C-number X is going to be compared to, X- number to compare.
nao_menor(X) :-
findall(N, num(N), L),
num(X),
I is 0,
nth0(I, L, C),
X =< C,
incr(I,I).

Here we go:
not_smallest(N) :-
num(N),
\+ \+ (num(M), M < N).
Sample queries as given by the OP:
?- not_smallest(5).
true.
?- not_smallest(X).
X = 1
; X = -2
; X = 5
; X = 50
; X = 87.

Related

How can I generate a list of numbers in between two parameters?

I am new to Prolog, and have been having some problems figuring out the syntax of the language. I want to create a method which takes 3 arguements of (X,Y,Z).
X is a list of all of the numbers in between Y and Z. I know that the base case should only return Y since Y+1 = Z. Then the recursive should keep incrementing Y until it is equal to Z while putting the numbers into a list.
Since I am new, I wanted to avoid using built-in libraries and predicates.
This is what I am working off of right now.
range(X,Y,Z):-
%If Y + 1 == Z, X is just Y
range(X,Y,Z) :-
Y =< Z,
D is Y+1,
range(X,D,Z).
%use recursion to go from Y to Z, then collect it in X
I realized a bit later that my expected results should look like this:
range(X,1,10) should return [1,2,3,4,5,6,7,8]
Here a simple solution:
range([],A,B):-
A > B.
range([A|T],A,B):-
A =< B,
A1 is A + 1,
range(T,A1,B).
First clause: if A is greater than B, the resulting list is empty ([]). Second clause: if A is less or equal than B, increment A by 1 and store the result in A1, unify the head of the list with A (see [A|T]), and recursively call the predicate with the remaining part of the list (T), A1, and B.
?- range(L,1,10).
L = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
false
?- range(L,10,1).
L = []
false
There are multiple use cases for something like this:
testing that an integer lies within a given range, and
generating a specified sequence of integers.
This covers both ascending ranges and descending ranges, so
range(1,5,X) will, on backtracking, unify X with 1,2,3,4,5.
range(5,1,X) will, on backtracking, unify X with 5,4,3,2,1.
range(1,5,9) tests whether or not 9 lies within the ascending range 1-5 (it does not).
range(5,1,3) tests whether or not 3 lies within the descending range 5-1 (it does).
% ==========================================================
% range/3: Tests that Z lies with the range X-Y,
% or generates the sequence of integers X-Y.
% Both ascending ranges (1-5) and descending ranges (5-1)
% are supported. X and Y must both be integers. Z must be
% either an integer or an unbound variable.
% ==========================================================
range( X , Y , Z ) :-
integer(X),
integer(Y),
range0(X,Y,Z).
% ==========================================================
% Private (helper) predicates)
% ==========================================================
% --------------------------
% range0/3: Traffic director
% --------------------------
range0( X , Y , Z ) :- integer(Z), !, range1(X,Y,Z) .
range0( X , Y , Z ) :- var(Z), !, range2(X,Y,Z) .
% ----------------------------------
% range1/3: Z is bound to an integer
% ----------------------------------
range1(Lo,Hi,N) :- N >= Lo, N =< Hi, !.
range1(Hi,Lo,N) :- N >= Lo, N =< Hi, !.
% --------------------------------------------
% range2/3: Z is unbound. Generate a sequence.
% --------------------------------------------
range2(X,Y,N) :- X =< Y, !, range_asc(Lo,Hi,N) .
range2(X,Y,N) :- X > Y, !, range_dsc(Lo,Hi,N) .
% --------------------------------------------------------
% range_asc/3: Generates an ascending sequence of integers
% --------------------------------------------------------
range_asc( Hi , Hi , Hi ) :- !.
range_asc( Lo , _ , Lo ) .
range_asc( Lo , Hi , N ) :- L1 is Lo+1, range_asc(L1,Hi,N) .
% --------------------------------------------------------
% range_dsc/3: Generates a descending sequence of integers
% --------------------------------------------------------
range_dsc( Lo , Lo , Lo ) :- !.
range_dsc( Hi , _ , Hi ) .
range_dsc( Hi , Lo , N ) :- H1 is Hi-1, range_dsc(H1,Lo,N) .

Prolog list of lists get all elements

I have a lists of lists:
decide([[1,2,-3],[-2,3],[6],[4]],K).
I want to return all the possible solutions pressing ';'.
The rule is to first return the values that its list has size 1.
Then I want to return the values that its size is bigger than 1.
size([],0).
size([_|Xs],L) :- size(Xs,N),L is N+1.
head([],[]).
head([X|_],X).
return_list_members([X|_], X).
return_list_members([_|T], X):-return_list_members(T, X).
decide([], []).
decide([L|Ls], Lit):- size(L, N), N == 1, head(L, Lit).
decide([L|Ls], Lit):- size(Ls, N), N == 0, head(L, Lit), !.
decide([L|Ls], Lit):- decide(Ls, Lit) ,return_list_members(Ls, Lit)
Example how should be the resulr:
? - decide([[1,2,-3],[-2,3],[6],[4]],K).
K = 6 ;
K = 4 ;
K = -2 ;
K = 3 ;
K = -3 ;
K = 2 ;
K = 1.
My goal is to return first the list with only one value. Then return all the elem of the others lists, one by one. The form I have the code, only return the first elem of the list, because I have the head call. How I can return not only the head values, but all the others, and without repetead? I tried to creat a function for return all the elem of the lists.
Any suggestion?
Taking your other question as a starting point, simply insert your new requirements:
listoflist_member(Xss, X) :-
( Xs = [_] ; Xs = [_,_|_] ), % new
member(Xs, Xss),
member(X, Xs).

Prolog - How to count the number of elements in a list that satisfy a specific condition?

for example, if I have a list [1,1,2,3,5,1], I want to count the number of 1's in this list, how would I do that?
I wrote something like:
count([], 0).
count([H|T], N) :-
count(T, X),
( H =:= 1
-> N is X+1
; N is X
),
N > 0.
In this recursion, I want to do if Head equals 1, then the counting + 1, if Head is not 1, then counting stays the same. However, it returns false if I have things that are not 1 in the list. I know the problem is that it'd fail as soon as an element does not satisfy the if statement; and it can never reach the else statement. How do I fix this? Please help!!!!
Try this:
count([],0).
count([1|T],N) :- count(T,N1), N is N1 + 1.
count([X|T],N) :- X \= 1, count(T,N).
Alternative solution, which uses foldl/4 and defines higher order predicate (the one which takes another predicate as a parameter):
count_step(Condition, Item, CurrentCount, NewCount) :-
call(Condition, Item) ->
NewCount is CurrentCount + 1 ;
NewCount = CurrentCount.
count(List, Condition, Count) :-
foldl(count_step(Condition), List, 0, Count).
is_one(Expr) :-
Expr =:= 1.
Usage example:
?- count([0, 2, 3, 0], is_one, Count).
Count = 0.
?- count([1, 2, 3, 1], is_one, Count).
Count = 2.
Another (rather dirty) approach is to use include/3 combined with length/2:
count(List, Condition, Count) :-
include(Condition, List, Filtered),
length(Filtered, Count).
Let’s start with your code and ask some queries!
I added comments on the side showing the result I would have expected...
?- count([0,2,3,0], Count).
false % bad: expected Count = 0
?- count([1,2,3,1], Count).
Count = 2 % ok
?- count([1,2,3], Count).
false % bad: expected Count = 1
If my expectation matches yours, the minimal fix for your code is tiny: just remove the goal N > 0!
count([], 0).
count([H|T], N) :-
count(T, X),
( H =:= 1
-> N is X+1
; N is X
).
Let’s run above queries again:
?- count([0,2,3,0], Count).
Count = 0 % was “false”, now ok
?- count([1,2,3,1], Count).
Count = 2 % was ok, still is ok
?- count([1,2,3], Count).
Count = 1. % was “false”, now ok
The bottom line: your original code failed whenever the last list item was not equal to 1.
Since you've already opted to use (;)/2 - if-then-else, you might find the following variant with if_/3 interesting:
list_1s(L,X) :-
length(L,Len),
list_1s_(L,X,0,Len).
list_1s_([],X,X,0).
list_1s_([Y|Ys],X,Acc0,Len1) :-
if_(Y=1, Acc1 is Acc0+1, Acc1 is Acc0),
Len0 is Len1-1,
list_1s_(Ys,X,Acc1,Len0).
The goal length/2 in the calling predicate list_1s/2 together with the 4th argument of the actual relation list_1s_/4 is used to make sure the result lists are listed in a fair manner if the predicate is called with the first argument being variable. The 3rd argument of list_1s_/4 is an accumulator that's used to count the number of 1s up from zero, in order to make the predicate tail recursive. Consequently the 2nd and 3rd arguments of list_1s_/4 are equal if the list is empty. Now let's see some example queries. In the list to number direction the predicate yields the desired results and succeeds deterministically (it doesn't leave unnecessary choice points open, no need to press ; after the single answer) in doing so:
?- list_1s([],X).
X = 0.
?- list_1s([1,2,3],X).
X = 1.
?- list_1s([1,2,3,1],X).
X = 2.
?- list_1s([0,2,3,0],X).
X = 0.
In the number to list direction there are infinitely many lists for any given number and, as mentioned above, they are listed in a fair manner, that is, all possibilities of lists of length n are listed before moving on to length n+1:
?- list_1s(L,0).
L = [] ; % <- empty list
L = [_G386], % <- length 1
dif(_G386, 1) ;
L = [_G442, _G445], % <- length 2
dif(_G442, 1),
dif(_G445, 1) ;
L = [_G498, _G501, _G504], % <- length 3
dif(_G498, 1),
dif(_G501, 1),
dif(_G504, 1) ;
.
.
.
?- list_1s(L,1).
L = [1] ; % <- length 1
L = [1, _G404], % <- length 2
dif(_G404, 1) ;
L = [_G401, 1], % <- length 2
dif(_G401, 1) ;
L = [1, _G460, _G463], % <- length 3
dif(_G460, 1),
dif(_G463, 1) ;
L = [_G457, 1, _G463], % <- length 3
dif(_G457, 1),
dif(_G463, 1) ;
L = [_G457, _G460, 1], % <- length 3
dif(_G457, 1),
dif(_G460, 1) ;
.
.
.
And the most general query is listing the results in a fair manner as well:
?- list_1s(L,X).
L = [], % <- empty list
X = 0 ;
L = [1], % <- length 1
X = 1 ;
L = [_G413], % <- length 1
X = 0,
dif(_G413, 1) ;
L = [1, 1], % <- length 2
X = 2 ;
L = [1, _G431], % <- length 2
X = 1,
dif(_G431, 1) ;
L = [_G428, 1], % <- length 2
X = 1,
dif(_G428, 1) ;
.
.
.

PROLOG Undefined procedure ERROR (Two parameters recursion)

count([], 0, 0).
count([X|T], M, N) :- 1 is X, count(T, MRec, NRec),
M is MRec, N is NRec+1.
count([X|T], M, N) :- 0 is X, count(T, MRec, NRec),
M is MRec+1, N is NRec.
control_number(L) :- count_digit(L, M, N), 2 is M, 3 is N.
?- control_number([1,1,0,0,1]).
ERROR: count_number/3: Undefined procedure: count/3
Hello everybody, I need help. This code must provide the count of two separate number recursively. However, I cannot provide recursion
with 2 parameters. I guess MRec and NRec is not valid in any way.
Any help will be appreciated. Thanks now...
Here is a more idiomatic rewrite:
count_digits([], 0, 0).
count_digits([1|T], M, N) :-
count_digits(T, M, NRec),
N is NRec+1.
count_digits([0|T], M, N) :-
count_digits(T, MRec, N),
M is MRec+1.
control_number(L) :-
count_digits(L, 2, 3).
This can be improved a lot by using library(clpfd). Maybe someone else will answer.
As already pointed out by #false this predicate is quite a candidate for clpfd. Besides that I added constraints (marked as % <-) to ensure that M and N are greater than 0 in the recursive cases, so Prolog does not continue to search for further solutions once those variables have been reduced to 0.
:- use_module(library(clpfd)).
count_digits([], 0, 0).
count_digits([1|T], M, N) :-
N #> 0, % <-
NRec #= N-1,
count_digits(T, M, NRec).
count_digits([0|T], M, N) :-
M #> 0, % <-
MRec #= M-1,
count_digits(T, MRec, N).
With these minor modifications you can already use count_digits/3 in several ways. For example to ask for all lists with 2 0's and 3 1's:
?- count_digits(L,2,3).
L = [1,1,1,0,0] ? ;
L = [1,1,0,1,0] ? ;
L = [1,1,0,0,1] ? ;
L = [1,0,1,1,0] ? ;
L = [1,0,1,0,1] ? ;
L = [1,0,0,1,1] ? ;
L = [0,1,1,1,0] ? ;
L = [0,1,1,0,1] ? ;
L = [0,1,0,1,1] ? ;
L = [0,0,1,1,1] ? ;
no
Or count the occurrences of 0's and 1's in a given list:
?- count_digits([1,1,0,0,1],M,N).
M = 2,
N = 3
% 1
Or even ask for the number of 0's and 1's in a list containing variables:
?- count_digits([1,0,X,Y],M,N).
M = X = Y = 1,
N = 3 ? ;
M = N = 2,
X = 1,
Y = 0 ? ;
M = N = 2,
X = 0,
Y = 1 ? ;
M = 3,
N = 1,
X = Y = 0
This is quite nice already and one might be content with the predicate as is. It certainly is fine if you intend to use it with control_number/1 as suggested by #false. However it might be worth the time to fool around a little with some other queries. For example the most general query: What lists are there with M 0's and N 1's?
?- count_digits(L,M,N).
L = [],
M = N = 0 ? ;
L = [1],
M = 0,
N = 1 ? ;
L = [1,1],
M = 0,
N = 2 ? ;
L = [1,1,1],
M = 0,
N = 3 ?
...
It is only producing lists that consist of 1's exclusively. That is because the first recursive rule is the one describing the case with the 1 as the first element of the list. So the solutions are coming in an unfair order. What happens with the following query is maybe even somewhat less intuitive: What lists are there with the same (but not fixed) number of 0's and 1's:
?- count_digits(L,M,M).
L = [],
M = 0 ? ;
There is an answer and then the predicate loops. That's not exactly a desirable property. An interesting observation about this query: If one uses it on lists with fixed length the result is actually as expected:
?- length(L,_), count_digits(L,M,M).
L = [],
M = 0 ? ;
L = [1,0],
M = 1 ? ;
L = [0,1],
M = 1 ? ;
L = [1,1,0,0],
M = 2 ? ;
L = [1,0,1,0],
M = 2 ? ;
...
Applying this idea to the previous query yields a fair ordering of the results:
?- length(L,_), count_digits(L,M,N).
L = [],
M = N = 0 ? ;
L = [1],
M = 0,
N = 1 ? ;
L = [0],
M = 1,
N = 0 ? ;
L = [1,1],
M = 0,
N = 2 ? ;
L = [1,0],
M = N = 1 ? ;
...
It certainly would be nice to get these results without having to prefix an auxiliary goal. And looking a little closer at the relation described by count_digits/3 another observation meets the eye: If there are M 0's and N 1's the length of the list is actually fixed, namely to M+N. To put these observations to work one could rename count_digits/3 to list_0s_1s/3 and redefine count_digits/3 to be the calling predicate with the following constraints:
:- use_module(library(clpfd)).
count_digits(L,M,N) :-
X #= M+N,
length(L,X), % L is of length M+N
list_0s_1s(L,M,N).
list_0s_1s([], 0, 0).
list_0s_1s([1|T], M, N) :-
N #> 0,
NRec #= N-1,
list_0s_1s(T, M, NRec).
list_0s_1s([0|T], M, N) :-
M #> 0,
MRec #= M-1,
list_0s_1s(T, MRec, N).
The first three queries above yield the same results as before but these two are now producing results in a fair order without looping:
?- count_digits(L,M,N).
L = [],
M = N = 0 ? ;
L = [1],
M = 0,
N = 1 ? ;
L = [0],
M = 1,
N = 0 ? ;
L = [1,1],
M = 0,
N = 2 ? ;
L = [1,0],
M = N = 1 ?
...
?- count_digits(L,M,M).
L = [],
M = 0 ? ;
L = [1,0],
M = 1 ? ;
L = [0,1],
M = 1 ? ;
L = [1,1,0,0],
M = 2 ? ;
L = [1,0,1,0],
M = 2 ?
...
Two last notes on your predicate control_number/1: Firstly, if you are using is/2 make sure to use it like so:
?- M is 2.
M = 2
% 1
instead of (as used in your definition of control_number/1):
?- 2 is M.
ERROR!!
INSTANTIATION ERROR- in arithmetic: expected bound value
% 1
And secondly, if you intend to use a predicate like control_number/1 to call count_digits/3, don't put goals like M is 2 and N is 3 after the actual call of count_digits/3. That way you are asking for all solutions of count_digits(L,M,N), of which there are infinitely many, and in the subsequent goals you are then filtering out the ones that satisfy your constraints (M is 2 and N is 3). With this ordering of the goals you make sure that control_number/1 does not terminate after producing the finite number of solutions, since infinitely many solution-candidates are produced by the first goal that subsequently fail according to your constraints. Instead, place such constraints first or put them directly as arguments into the goal as posted by #false.
Accumulation parameters is the way to go (you need an auxiliary predicate in order to initialize those parameters):
count(List,C0,C1) :-
count_aux(List,C0,C1,0,0).
count_aux([],C0,C1,C0,C1).
count_aux([0|Rest],C0,C1,PartialC0,PartialC1) :-
IncC0 is PartialC0+1,
!,
count_aux(Rest,C0,C1,IncC0,PartialC1).
count_aux([1|Rest],C0,C1,PartialC0,PartialC1) :-
IncC1 is PartialC1+1,
!,
count_aux(Rest,C0,C1,PartialC0,IncC1).
count_aux([_|Rest],C0,C1,PartialC0,PartialC1) :-
count_aux(Rest,C0,C1,PartialC0,PartialC1).
Note:
You should call count/3, not count_aux/5.
Last two parameters to count_aux/5 are accumulation parameters
initialized to zero.
First clause to count_aux/5 is the base case, where accumulated
parameters are returned.
Last clause to count_aux/5 prevents predicate failure if list items
are not 0 nor 1.
Example:
?- count([1,1,0,0,0,k],A,B).
A = 3,
B = 2.

Prolog converting integer to a list of digit

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).
I think this is easier:
numToList(NUM,[LIST|[]]):-
NUM < 10,
LIST is NUM,
!.
numToList(NUM,LIST):-
P is NUM // 10,
numToList(P,LIST1),
END is (NUM mod 10),
append(LIST1,[END] ,LIST).
As already suggested, consider using finite domain constraints:
:- use_module(library(clpfd)).
number_digits(Number, 0, [Number]) :- Number in 0..9.
number_digits(Number, N, [Digit|Digits]) :-
Digit in 0..9,
N #= N1 + 1,
Number #= Digit*10^N + Number1,
Number1 #>= 0,
N #> 0,
number_digits(Number1, N1, Digits).
This predicate can be used in all directions. Examples with either argument instantiated:
?- number_digits(215, _, Ds).
Ds = [2, 1, 5] ;
false.
?- number_digits(N, _, [4,3,2,1]).
N = 4321 ;
false.
And two more general queries:
?- number_digits(N, _, [A,B]).
N in 10..99,
_G2018+B#=N,
_G2018 in 10..90,
A*10#=_G2018,
A in 0..9,
B in 0..9 ;
false.
?- number_digits(N, _, Ds).
Ds = [N],
N in 0..9 ;
Ds = [_G843, _G846],
N in 0..99,
_G870+_G846#=N,
_G870 in 0..90,
_G843*10#=_G870,
_G843 in 0..9,
_G846 in 0..9 ;
etc.
Here comes yet another variant based on clpfd... Based on (#=)/3 and if_//3 we define:
n_base_digits(N, R, Ds) :-
N #> 0, % positive integers only
R #> 1, % smallest base = 2
Ds = [D|_], % leading digit may not be 0
D #> 0,
phrase(n_base_digits_aux(N, R, Ds), Ds).
n_base_digits_aux(N, Base, [_|Rs]) -->
{ D #= N mod Base,
M #= N // Base },
if_(M #= 0,
{ Rs = [] },
n_base_digits_aux(M, Base, Rs)),
[D].
Query using SICStus Prolog 4.3.3:
| ?- n_base_digits(1234, 10, Ds).
Ds = [1,2,3,4] ? ;
no
Works the other way round, too!
| ?- n_base_digits(I,10,[1,2,3]).
I = 123 ? ;
no
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:
my_digits(Number, List) :-
atomic_list_concat(List, Atom),
atom_number(Atom, Number).
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 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!
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.
: -- int_2_digits/2 ------------------------------------------------------------
:
: The public api.
:
: we've got 2 special cases here:
:
: * zero, and
: * negative numbers
:
: and, of course, the general case: a positive value.
:
: ------------------------------------------------------------------------------
int_2_digits( 0 , [0] ) . : zero is a special case
int_2 digits( X , ['-'|Ds] ) :- : negative numbers are a special case
X < 0 , : which we handle (YMMV) by prepending the
X1 is - X , : sign and than processing the absolute value
int_2_digits(X1,Ds) . :
int_2_digits( X , Ds ) :- : the general case is a positive value
X > 0 , : just invoke the worker predicate.
int_2_digits(X,[],Ds) . :
: -- int_2_digits/3 ------------------------------------------------------------
:
: The guts of the operation.
:
: We're using an accumulator here because we compute the result right-to-left,
: from least significant digit to most significant digit. Using the accumulator
: builds the list in the correst sequence, so we don't have to reverse it at
: the end.
: ------------------------------------------------------------------------------
int_2_digits( 0 , Ds , Ds ) . : if we hit zero, we're done. Unify the accumulator with the result
int_2_digits( X , Ts , Ds ) :- : otherwise...
D is mod(X,10) , : - get the current digit (X modulo 10)
T is div(X,10) , : - get the next value via integer division
int_2_digits( X1 , [T|Ts] , Ds ) : - recurse down
. : Easy!