Search code examples
prologlogic-programmingclpfd

Shortest way to define multiple rules in prolog


I'm trying to solve an exercise in order to become more familiar with prolog.

The task is following:

% Sten wants to send Lisa 100 flowers. He can choose from lilies, roses and tulips.
% One lily costs $50, rose $10 and tulip $1. Find how many flowers of each type he 
% must buy, so that he spends exactly $500.

I have solved that exercise, but in somewhat bulky way I guess. My code is:

% numbers 1..100
digit(1). digit(2). digit(3). digit(4). digit(5). digit(6). digit(7). digit(8).
digit(9). digit(10). digit(11). digit(12). digit(13). digit(14). digit(15). digit(16). 
digit(17). digit(18). digit(19). digit(20). digit(21). digit(22). digit(23). digit(24). 
digit(25). digit(26). digit(27). digit(28). digit(29). digit(30). digit(31). digit(32). 
digit(33). digit(34). digit(35). digit(36). digit(37). digit(38). digit(39). digit(40).
digit(41). digit(42). digit(43). digit(44). digit(45). digit(46). digit(47). digit(48). 
digit(49). digit(50). digit(51). digit(52). digit(53). digit(54). digit(55). digit(56). 
digit(57). digit(58). digit(59). digit(60). digit(61). digit(62). digit(63). digit(64). 
digit(65). digit(66). digit(67). digit(68). digit(69). digit(70). digit(71). digit(72). 
digit(73). digit(74). digit(75). digit(76). digit(77). digit(78). digit(79). digit(80).
digit(81). digit(82). digit(83). digit(84). digit(85). digit(86). digit(87). digit(88). 
digit(89). digit(90). digit(91). digit(92). digit(93). digit(94). digit(95). digit(96). 
digit(97). digit(98). digit(99). digit(100).

quantity(A1,A2,A3):-
    var(A1), var(A2), var(A3),
    digit(A1), digit(A2), digit(A3),
    X is A1+A2+A3, X is 100,
    Y is (A1*50)+(A2*10)+(A3*1), Y is 500.

Can somebody suggest a better method for initializing those rules? For example in Haskell I could do something like this:

let numbers = [1..100]

Thanks in advance.


Solution

  • Some versions of Prolog have the between/3 predicate. You could say

    digit(X):-between(1,100,X).
    

    If between is not available, you could say

    digit(X):-member(X,[1,2,3,4,5 and so on]).
    

    If you do not want to use member/2, use recursion.

    Edit: you can also implement between/3 like this:

    my_between(X,Y,Z):-X<Y,(Z=X;X2 is X+1,my_between(X2,Y,Z)).
    

    A robust and efficient implementation of between/3 may be more complicated, but for your purposes, this should be enough.