I want to write a function in Racket which takes an amount of money and a list of specific bill-values, and then returns a list with the amount of bills used of every type to make the given amount in total. For example (calc 415 (list 100 10 5 2 1))
should return '(4 1 1 0 0)
.
I tried it this way but this doesn't work :/ I think I haven't fully understood what you can / can't do with set!
in Racket, to be honest.
(define (calc n xs)
(cond ((null? xs) (list))
((not (pair? xs))
(define y n)
(begin (set! n (- n (* xs (floor (/ n xs)))))
(list (floor (/ y xs))) ))
(else (append (calc n (car xs))
(calc n (cdr xs))))))
Your procedure does too much and you use mutation which is uneccesary. If you split the problem up.
Then you can make:
Then you can reduce your original implememntation like this:
This will always choose the solution with fewest bills, just as your version seems to do. Both versions requires that the last element in the
bill
passed is the unit1
. For a more complex method, that works with(calc 406 (list 100 10 5 2))
and that potentially can find all combinations of solutions, see Will's answer.This problem calls for some straightforward recursive non-deterministic programming.
The code here will follow another answer of mine, which finds out the total amount of solutions (which are more than one, for your example as well). We will just have to maintain the solutions themselves as well, whereas the code mentioned above only counted them.
We can code this one as a recursively backtracking procedure, with a callback to be called with each successfully found solution:
It is to be called through one of
Testing,
Regarding how this code is structured, cf. How to generate all the permutations of elements in a list one at a time in Lisp? It creates nested loops with the solution being accessible in the innermost loop's body.
Regarding how to code up a non-deterministic algorithm (making all possible choices at once) in a proper functional way, see How to do a powerset in DrRacket? and How to find partitions of a list in Scheme.
I think this is the first program I wrote when learning FORTRAN! Here is a version which makes no bones about using everything Racket has to offer (or, at least, everything I know about). As such it's probably a terrible homework solution, and it's certainly prettier than the FORTRAN I wrote in 1984.
Note that this version doesn't search, so it will get remainders even when it does not need to. It never gets a remainder if the lowest denomination is 1, of course.
I solved it this way now :)
Testing: