3
votes

I was writing a prolog predicate to print possible changes for given value, on running it shows a warning that X2 is a singleton variable. X is the given value, T is given List of available denominations and L is the resulting List.

e.g: change(100,[1,2,5,10],L).

change(X,T,L) :-
    change1(X,T,[],L).
change1(X,[H|T],AC,L):-
    X > 0,
    X >= H,
    X2 is X-1,
    change1(X2,T,[H|AC],L);
    change1(X2,[H|T],[H|AC],L);
    change1(X,T,AC,L).
change1(0,_,AC,AC).
change1(X,[],_,_):-X \= 0,false.
2

2 Answers

2
votes

You're getting a singleton warning because the comma , has higher precedence than ;, so the effective grouping of your code is:

change1(X,[H|T],AC,L):-
    (   X > 0,
        X >= H,
        X2 is X-1,
        change1(X2,T,[H|AC],L)
    )
    ;   change1(X2,[H|T],[H|AC],L)
    ;   change1(X,T,AC,L).

(note the parentheses) which isolates change1(X2,[H|T],[H|AC],L) from any queries that might instantiate X2. So X2 is singleton in that context. You probably meant:

change1(X,[H|T],AC,L):-
    X > 0,
    X >= H,
    X2 is X-1,
    (   change1(X2,T,[H|AC],L)
    ;   change1(X2,[H|T],[H|AC],L)
    ;   change1(X,T,AC,L)
    ).
2
votes

Use !

:- use_module([library(clpfd),library(lists)]).
:- set_prolog_flag(toplevel_print_anon, false).

We define change_/4 like this:

change_(Total, Units, Amounts, Zs) :-
   same_length(Units, Amounts),
   Units   ins 1..sup,
   Amounts ins 0..sup,
   scalar_product(Units, Amounts, #=, Total),
   append( [Total|Units],Amounts, Zs).

Sample query:

?- change_(100, [1,2,5,10], Amounts, _Zs), labeling([], _Zs).
  Amounts = [0,0,0,10]
; Amounts = [0,0,2,9]
; Amounts = [0,0,4,8]
...