Simplifying a Racket function - lisp

I have the following function "change" which takes a certain amount of money to be paid, the size of the bill/coin used to pay, and returns a list with the number of "coins" ($50, $20 $10 $5 $2 and $1) one would receive after completing the transaction:
(define (change total payment)
(let [(x (- payment total))]
(change-aux x '(50 20 10 5 2 1))))
(define (change-aux change coins)
(cond
[(empty? coins) empty]
[else (let [(num-coins (floor (/ change (car coins))))]
(append (list num-coins)
(change-aux (- change (* (car coins) num-coins)) (cdr coins))))]))
So, if I input these parameters:
> (change 44 200)
It returns the output:
'(3 0 0 1 0 1)
That's 200-44 = 156, which corresponds to 3 coins worth $50, 1 worth $5 and 1 worth $1.
My question would be if there's a more elegant, simplified way to write a similar procedure without relying on auxiliary functions, and rather use lambda, filter, map, foldr, foldl etc?
Thanks in advance.

Here is a solution in a different Lisp dialect which shows how to do it with a left fold (reduce) without any mutation of an accumulator variable, as a kind of functional counterpoint to the existing solution.
(defun change (amount coins)
(reduce-left (tb ((counts . rem) next-coin)
(let* ((coin-count (floor rem next-coin))
(coin-value (* coin-count next-coin)))
(cons (cons coin-count counts)
(- rem coin-value))))
coins
(cons '() amount)))
3> (change 156 '(50 20 10 5 2 1))
((1 0 1 0 0 3) . 0)
4> (change 88 '(50 20 10 5 2 1))
((1 1 1 1 1 1) . 0)
Note that the values end up reported in reverse order and wrapped in an extra cons cell; a "porcelain" function could be used around this "plumbing" to report the result in the expected form.
The idea is that we have an accumulator which looks like this: (counts . remainder). The counts part of the accumulator stored in the car is the list of coins accumulated so far. When the reduce is done, this holds the final list. The cdr field holds the remaining amount to be processed; since the last coin is 1, this will always emerge as zero.
Using this accumulator structure, we process the list of coins.
On each call to our reduce kernel function, the left argument is the accumulator, and the right argument, next-coin, is the next coin denomination value.
I used a macro called tb ("tree bind") macro, which is a kind of lambda that provides built-in destructuring, to make it look like we have three parameters.
The initial value for the reduce job is the starting accumulator, which has an empty list of coins, and the full original amount: (cons nil amount) (which I rewrote to (cons '() amount) for better Scheme compatibility).
The reduce function is very simple: greedily calculate how many of the next coin value are needed to represent the remainder, and then calculate the new remainder, packaging these up into a new accumulator cons cell that is returned, and is passed to the next invocation of the function, or returned when the list of coin values has been processed.
Hopefully this points the way to "a more elegant, simplified way to write a similar procedure without relying on auxiliary functions, and rather use lambda, filter, map, foldr, foldl etc" that you can work out in Racket. Good luck!

Sure, you can.
Final solution
(define (change total payment (coins '(50 20 10 5 2 1)))
(let ((rest-diff (- payment total)))
(map (lambda (coin)
(let ((num-coins (floor (/ rest-diff coin))))
(set! rest-diff (- rest-diff (* num-coins coin)))
num-coins))
coins)))
Step by step
First of all, using inner define, you can get rid of the auxiliary function from the global namespace.
(define (change total payment)
(define (change-aux change coins)
(cond
[(empty? coins) empty]
[else (let [(num-coins (floor (/ change (car coins))))]
(append (list num-coins)
(change-aux (- change (* (car coins) num-coins)) (cdr coins))))]))
(let [(x (- payment total))]
(change-aux x '(50 20 10 5 2 1))))
Then, you can pull some variables of the helper function's to the global function's lambda list.
(define (change total payment (coins '(50 20 10 5 2 1)))
(define (change-aux change) ;; eliminate coins in the inner lambda list
(cond
[(empty? coins) empty] ;; coins in function body looked up from outer arguments
[else (let [(num-coins (floor (/ change (car coins))))]
(append (list num-coins)
(change-aux (- change (* (car coins) num-coins)) (cdr coins))))]))
(let [(x (- payment total))]
(change-aux x))) ;; eliminate coins in the call
Then, looking at the code of change-aux, one understands this is actually
a looping through and trying to fit maximal multiples of current value
into the rest of the difference remaining - and collecting those reults. One could loop using map and use set! to mutate the rest.
(define (change total payment (coins '(50 20 10 5 2 1)))
(let ((rest-diff (- payment total)))
(map (lambda (coin)
(let ((num-coins (floor (/ rest-diff coin))))
(set! rest-diff (- rest-diff (* num-coins coin)))
num-coins))
coins)))
Then, you call like above:
(change 44 200)
;; '(3 0 0 1 0 1)

Related

DrRacket - Find Largest Number in a set

(for judges ([judge1 judge2 judge3 judge4 judge5 judge6 judge7 judge8])
(define i 0)
(define j 1)
(cond [(< judges[i] judges[j])
(cond [(equal? judges[j] judges(length))
(define highest-score judges[j])]
[else
(judges[i] judges[j])
(judges[j] judges[j +1])])]
[else
(cond [(equal? judges[i] judges[length -1])
(define highest-score judges[i])]
[else
(judges[j] judges[j +1])])]))
I want to be able to find the largest number in a set of values, which for this problem includes values from judge1, judge2... judge8. The way I'm trying to solve this problem is by taking the first two numbers on a list and comparing them; I can't seem to find much on DrRacket documentation on proper syntax for the type of operation I want to perform.
An easy way (in terms of writing code) to find the the maximum element is to sort the list, and grab the last element of that list. As #pdoherty926 mentioned, the easiest way to sort a list in Racket is with the sort function. You just give it a list and a comparitor, and it sorts the list for you:
> (sort '(5 2 6 1) <)
'(1 2 5 6)
And since you want the max value just grab the last element:
> (last (sort '(5 2 6 1) <))
6
Although if you want to find the maximum value of other (non-list) data structures, for is an attractive option. While your algorithm looks good, your syntax is off. In this particular case, I would actually recommend using for/fold. Basically, it lets you have an accumulator, which will hold your highest judge so far, as well as the list of judges you are iterating through, and the body for how you want to modify the accumulator. In this case, your loop will look something like:
;; A judge is a non-negative number
(define judges '(5 6 1 2))
(for/fold ([largest -1])
([j (in-list judges)])
...)
Where you replace the ... with the next value for largest. The entire loop evaluates to the final value for largest.
The interesting thing here is that j is an actual judge, not just an index to the judges list. So your body does not need to refer to the judges list at all. It should look something like:
(max j largest)
Since a judge is just a number. I will leave you to put the body in the loop as an exercise.
As an aside, since judges are just numbers, you can just use max directly with apply:
> (apply max '(5 6 1 2))
6
As one additional note, if for some reason you do want the actual index of the current judge you are examining, you can use in-naturals:
(for/fold ([largest -1])
([j (in-list judges)]
[index (in-naturals)])
...)
Following recursive function also works to find largest number in a list:
(define (largestnum slist)
(cond
((= (length slist) 2) ; if only 2 numbers, compare them
(if (> (car slist) (list-ref slist 1))
(car slist)
(list-ref slist 1)))
(else ; else recurse to compare car with largest of cdr
(let ((cdrLargest (largestnum (cdr slist))))
(if (> (car slist) cdrLargest)
(car slist)
cdrLargest)))))
(define judges '(5 6 1 2))
(largestnum judges)
Output:
6

check even digits on even positions in number lisp

I need a function that will check if all digits in some number on even positions are even. The least significant digit is on position 1, starting from right to left. The function need to be written in lisp.
Examples:
245 -> true, since 4 is even
238456 -> false, since 5 is odd and 8 and 2 are even
and so on...
Here`s what I got:
(defun check(number fac)
(cond
((= (/ number fac) 0) t)
((= (mod (/ number fac) 2 ) 0) (check number (* 100 fac) ) )
(nil)))
The initial value for fac is 10, we divide the number with 10, extract the second digit, check if it is even, if so proceed and divide number with 1000 to extract the 4-th digit and so on until we get over all digits, than the function returns true, meanwhile if some digit is odd the function should return nil.
But something is wrong and the function return nil all the time , when I call it like (check 22 10) for example.
Any thoughts?
Here is a non recursive solution that checks for the correctness of the parameter:
(defun check(num)
(assert (integerp num))
(loop for i = (truncate num 10) then (truncate i 100) until (zerop i)
always (evenp i)))
Just another variant. Basicly I'm converting number to list (through string though, maybe not the best way), then reverse it, select every second element and check it all for being even.
;; Helper for getting every
(defun get-all-nth (list period)
"Get all NTH element in the list"
(remove-if-not
(let ((iterator 0))
(lambda (x)
(declare (ignore x))
(= 0 (mod (incf iterator) period)))) list))
(defun check-evens (num)
"Checks if all digits in some number on even positions are even.
Goes Rigth-to-left."
(assert (integerp num))
(every #'evenp
(get-all-nth
(reverse
(map 'list #'digit-char-p
(prin1-to-string num))) 2)))
Some test cases:
CL-USER> (check-evens 123)
T
CL-USER> (check-evens 238456)
NIL
CL-USER> (check-evens 238446)
T
CL-USER> (check-evens 23844681)
T

Looping through a list and appending to a new one

I'm new to Lisp. I'm trying to write a function that will take a list of dotted lists (representing the quantities of coins of a certain value), e.g.
((1 . 50) (2 . 20) (3 . 10)) ;; one 50 cent coin, two 20 cent coins, three 10 cent coins
and then convert it to list each coin by value, e.g.
(50 20 20 10 10 10)
Shouldn't be too hard, right? This is what I have so far. It returns NIL at the moment, though. Any ideas on fixing this?
(defun fold-out (coins)
(let ((coins-list (list)))
(dolist (x coins)
(let ((quantity (car x)) (amount (cdr x)))
(loop for y from 0 to quantity
do (cons amount coins-list))))
coins-list))
Since you can use loop, simply do
(defun fold-out (coins)
(loop
for (quantity . amount) in coins
nconc (make-list quantity :initial-element amount)))
alternatively, using dolist:
(defun fold-out (coins)
(let ((rcoins (reverse coins)) (res nil))
(dolist (c rcoins)
(let ((quantity (car c)) (amount (cdr c)))
(dotimes (j quantity) (push amount res))))
res))
If I were to do this, I'd probably use nested loops:
(defun fold-out (coins)
(loop for (count . value) in coins
append (loop repeat count
collect value)))
Saves a fair bit of typing, manual accumulating-into-things and is, on the whole, relatively readable. Could do with more docstring, and maybe some unit tests.
The expression (cons amount coins-list) returns a new list, but it doesn't modify coins-list; that's why the end result is NIL.
So you could change it to (setf coins-list (cons amount coins-list)) which will explicitly modify coins-list, and that will work.
However, in the Lisp way of doing things (functional programming), we try not to modify things like that. Instead, we make each expression return a value (a new object) which builds on the input values, and then pass that new object to another function. Often the function that the object gets passed to is the same function that does the passing; that's recursion.

Lisp, sub total of a numbers in a nested list

i have a problem that i just cant work out,
the user enters a list ie
(total-cost
'((anItem 2 0.01)
(item 3 0.10)
(anotherItem 4 4.10)
(item 5 2.51)))
i need to add the number on the end together and then return the result
my current code returns the code after each addition. and also throws a error about unexpected type
(defun total-cost (list)
(loop with sum = 0
for x in list
collect (setf sum (+ sum (last x)))
)
)
Error: (0.01)' is not of the expected typeNUMBER'
Any help is appreciated
Thanks Dale
Using LOOP:
CL-USER 19 > (loop for (nil nil number) in '((anItem 2 0.01)
(item 3 0.10)
(anotherItem 4 4.10)
(item 5 2.51))
sum number)
6.72
REDUCE is another option:
CL-USER 20 > (reduce '+
'((anItem 2 0.01)
(item 3 0.10)
(anotherItem 4 4.10)
(item 5 2.51))
:key 'third)
6.72
Loop has a keyword sum for summing so you don't have to have an explicit variable nor use setf:
(defun total-cost (list)
(loop for x in list sum (third x)))
As Chris said, use (car (last x)) if the number you're looking for is always the last one. Or you can use (third x) as in my example if it's always the third one.
Also, note that the use of collectis wrong if your aim is to return the sum only; your example (corrected) returns
(0.01 0.11 4.21 6.7200003)
whereas mine returns
6.7200003
Note that if you want so escape the rounding errors as much as possible you need to use an exponent marker to make them double-floats for example:
(total-cost '((anItem 2 0.01D0)
(item 3 0.10D0)
(anotherItem 4 4.10D0)
(item 5 2.51D0)))
=> 6.72D0
last returns the last cons cell in the list, not its value. You need to use (car (last x)) instead.
Just in case you want the code to give you a precise result rather then being short:
(defun kahan-sum (floats)
(loop
:with sum := 0.0 :and error := 0.0
:for float :in floats
:for epsilon := (- float error)
:for corrected-sum := (+ sum epsilon) :do
(setf error (- corrected-sum sum epsilon) sum corrected-sum)
:finally (return sum)))
(defun naive-sum (floats) (loop :for float :in floats :sum float))
(let ((floats (loop :repeat 1000 :collect (- (random 1000000.0) 1000000.0))))
(format t "~&naive sum: ~f, kahan sum: ~f" (naive-sum floats) (kahan-sum floats)))
;; naive sum: -498127420.0, kahan sum: -498127600.0
Read more about why it works like this here: http://en.wikipedia.org/wiki/Kahan_summation_algorithm
Coming late to the party... How about a little lisping instead of looping? ;-)
(defun sum-3rd (xs)
(let ((sum 0))
(dolist (x xs sum)
(incf sum (nth 2 x)))))

create racket accumulator "variable"

Im really having problems understanding how I can create variable that would act as an accumulator in racket. This is definitely a really stupid question....but racket's documentation is pretty difficult for me to read.
I know I will use some kind of define statement or let statement.
I want to be able to pass a number to a variable or function and it adds the current value with the new value keeps the sum...How would I do this....?? Thank you..
(define (accumulator newvalue) "current=current+newvalue"
something like this..
An accumulator is generally just a function parameter. There are a few chapters in How to Design Programs (online, starting here) that cover accumulators. Have you read them?
For example, the reverse function is implemented using an accumulator that remembers the prefix of the list, reversed:
;; reverse : list -> list
(define (reverse elems0)
;; reverse/accum : list list -> list
(define (reverse/accum elems reversed-prefix)
(cond [(null? elems)
reversed-prefix]
[else
(reverse/accum (cdr elems)
(cons (car elems) reversed-prefix))]))
(reverse/accum elems null))
Note that the scope of the accumulator reversed-prefix is limited to the function. It is updated by calling the function with a new value for that parameter. Different calls to reverse have different accumulators, and reverse remembers nothing from one call to the next.
Perhaps you mean state variable instead. In that case, you define it (or bind it with let or lambda) at the appropriate scope and update it using set!. Here's a global state variable:
;; total : number
(define total 0)
;; add-to-total! : number -> number
(define (add-to-total! n)
(set! total (+ total n))
total)
(add-to-total! 5) ;; => 5
(add-to-total! 31) ;; => 36
Here's a variation that creates local state variables, so you can have multiple counters:
;; make-counter : -> number -> number
(define (make-counter)
(let ([total 0])
(lambda (n)
(set! total (+ total n))
total)))
(define counterA (make-counter))
(define counterB (make-counter))
(counterA 5) ;; => 5
(counterB 10) ;; => 10
(counterA 15) ;; => 20
(counterB 20) ;; => 30
But don't call state variables accumulators; it will confuse people.
Do you mean something like this?
(define (accumulator current newvalue)
(let ((current (+ current newvalue)))
...)
You can close over the accumulator variable:
(define accumulate
(let ((acc 0))
(λ (new-val)
(set! acc (+ acc new-val))
acc)))
(accumulate 10) ;=> 10
(accumulate 4) ;=> 14