I found the following code (in this blog post that solves the Coin Changer Kata):
(defn change-for [amount]
(let [denominations [25 10 5 1]
amounts (reductions #(rem %1 %2) amount denominations)
coins (map #(int (/ %1 %2)) amounts denominations)]
(mapcat #(take %1 (repeat %2)) coins denominations)))
The part I find difficult is: (reductions #(rem %1 %2) amount denominations)
.
As I found out, reductions just calculates the resulting collection incrementally based on some given function. Example: (reductions + [1 2 3])
gives [1 3 6]
.
1 ; first element
1 + 2 ; second element
1 + 2 + 3 ; third element
The next function, rem which calculates the remainder is still extremely simple to understand.
To understand the rest of the code I tried the following:
; first try, to see if this call works
; outside the original code (the change-for function)
(reductions #(rem %1 %2) 17 [10 5 1]) ; --> [17 7 2 0]
; tried to use the reductions which takes only one argument
; notice that 17 is now inside the array
(reductions #(rem %1 %2) [17 10 5 1]) ; --> [17 7 2 0]
; further simplified the expression
(reductions rem [17 10 5 1]) ; --> [17 7 2 0]
The last step was to remove the anonymous function as described in this blog post.
Here, things get confusing (at least for me): rem
takes 2 arguments and I don't get it how they are applied when using the array [17 10 5 1]
. I tried the following calls:
(rem [17 10 5 1]) ; --> gives error
(rem [17 10 5 1] [17 10 5 1]) ; --> also gives error
(rem 17 10) ; --> works, but how do you use it with collections?
Can someone explain me, how this rem
function works with the reductions
function?
Another thing I don't quite understand is: how are those percent arguments applied (in #(rem %1 %2)
)? I mean where do they come from? I tried calling rem
in the following way, but I get an error: (#(rem %1 %2) 17 [10 5 1])
. There must be something the reductions
function is doing behind the scenes to make this work, right?
At first I thought that #(rem %1 %2)
was a set. These are declared in a similar way as sets and can be easily misused (by someone just starting out with Clojure):
(type #{1 2 3}) ; --> clojure.lang.PersistentHashSet
(type #(1 2 3)) ; --> user$eval12687$fn__12688
Can someone point me to a site/book/whatever that explains Clojure tricks such as "The Special Form for an Anonymous Function"? Most resources just give the simplest constructs (the ones similar to all the other lisp derivatives) without going into the intricacies of Clojure. I found a site which looks pretty good (and also explains the anonymous functions I mentioned above). Any other such resources?
This:
(reductions #(rem %1 %2) amount denominations)
is equivalent to this:
(reductions rem amount denominations)
and as you noticed
(reductions function start collection)
returns a sequence of intermediate results of reducing the collection
with function
(taking start
as the first argument of the first step of reduction). function
must take two parameters.
So the result of:
(reductions function start [1 2 3 4 5])
is
((function start 1) (function (function start 1) 2) ...)
The #(rem %1 %2)
syntax is just a shorthand for defining anonymous function that takes two parameters (%1
and %2
), calls rem
on them and returns the result.
It's equivalent to:
(fn [a b] (rem a b))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With