I am working on the solution for this koan, which states:
Write a function which replicates each element of a sequence a variable number of times.
To do this, I want to:
With that in mind, I wrote the following method:
(fn dupSeqX [aseq x]
(fn dupx [v x]
(if (= x 1) (list v) (concat v (dupx v (- x 1))))
)
(reverse (reduce #(concat %1 (dupx %2 x)) '() aseq)))
When running this code, I get the following error:
java.security.PrivilegedActionException: java.lang.Exception: Unable to resolve symbol: dupx in this context (NO_SOURCE_FILE:0)
How do I go about creating a local method that will allow me to finish this koan?
Is there a "clojure-esque" way of doing this that I'm not aware of?
First of all, we don't talk about methods: we talk about functions. There is something in clojure that you could call a method but it's different from a function. If you stop using the OO lingo you will lose the OO style of thinking too.
What you are trying to do is possible. You basiclly want to create a new function with the name dupx in the dupseqx function. What you are doing right now is creating a function and then throwing it away (you don't do anything with the return value and only the last form in a function gets returned). Since a function is just like any other value, you can use the same mecanism like with any other value: create a local "variable". What's the mechanism for this? It's local binding and it works like this (The name in the fn is just so that you can call it from itself; it doesn't need to be the same as the let-bound name):
(let [dupx (fn dupx [v x]
(if (= x 1)
(list v)
(cons v (dupx v (dec x)))))]
(dupx 5 3))
Notice that I corrected some other things.
A shorter form of this (fixing the double name ugliness):
(letfn [(dupx [v x] (if (= x 1)
(list v)
(cons v (dupx v (dec x)))))]
(dupx 5 3))
Ok in everything between "(let [...]" and the matching ")" we now have a dupx function.
So now the rest of your code works:
(fn dupSeqX [aseq x]
(letfn [(dupx [v x] (if (= x 1) (list v) (cons v (dupx v (dec x)))))]
(reverse (reduce #(concat %1 (dupx %2 x)) '() aseq))))
This code can be made a little more idiomatic:
coll instead of aseqHow did I go about writing this?
First the basic fn. coll is the standard for naming function that expect sequences.
(fn [coll times] )
If you read this "each element of a sequence" your brain has to go MAP.
(fn [coll times]
(map (fn ....) coll))
"replicates each ... " is basically a description of what you have to put into the map function. We can use repeat (your dubx function but with some extra goodies like that it's lazy).
(fn [coll times]
(map (fn [val] (repeat times val)) coll))
There is one problem left (from the koan). It wants one seq back, not a sequence in a sequence for each element. This means we have to concat the result together.
(fn [coll times]
(apply concat (map (fn [val] (repeat times val)) coll)))
You will often see the (apply concat (map ....)) pattern. There is a better function for that in the standard library, called mapcat, and I'll make the inner function into the short syntax.
(fn [coll times]
(mapcat #(repeat times %) coll))
Hope that helps!
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