Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly use "iterate" and "partial" in Clojure?

Most reference to iterate are for operators, and all the applications on functions are so confusing that I still don't get how to use iterate in my code, and what partial is.

I am doing a programming homework, trying to use Newton's method to get square root for a number n. That is, with guess as the initial approximation, keep computing new approximations by computing the average of the approximation and n/approximation. Continue until the difference between the two most recent approximations is less than epsilon.

I am trying to do the approximation part first, I believe that is something I need to use iterate and partial. And later the epsilon is something I need to use "take"?

Here is the code I have for approximation without the epsilon:

(defn sqrt [n guess]
  (iterate (partial sqrt n) (/ (+ n (/ n guess)) 2)))

This code does not work properly though, when I enter (sqrt 2 2), it gives me (3/2 user=> ClassCastException clojure.lang.Cons cannot be cast to java.lang.Number clojure.lang.Numbers.divide (Numbers.java:155).

I guess this is the part I need to iterate over and over again? Could someone please give me some hints? Again, this is a homework problem, so please do not provide me direct solution to the entire problem, I need some ideas and explanations that I can learn from.

like image 640
zaolian Avatar asked Nov 03 '13 05:11

zaolian


2 Answers

partial takes a function and at least one parameter for that function and returns a new function that expects the rest of the parameters.

(def take-five (partial take 5))
(take-five [1 2 3 4 5 6 7 8 9 10])
;=> (1 2 3 4 5)

iterate generates an infinite sequence by taking two parameters: a function and a seed value. The seed value is used as the first element in the generated list and the second is computed by applying the function to the seed, the second value is used as the input for the function to get the third value and so on.

(take-five (iterate inc 0))
;=> (0 1 2 3 4)

ClojureDocs offers good documentation on both functions: http://clojuredocs.org/clojure_core/clojure.core/iterate and http://clojuredocs.org/clojure_core/clojure.core/partial.

like image 126
ponzao Avatar answered Nov 15 '22 08:11

ponzao


So, @ponzao explained quite well what iterate and partial do, and @yonki made the point that you don't really need it. If you like to explore some more seq functions it's probably a good idea to try it anyways (although the overhead from lazy sequences might result in a somewhat not ideal performance).

Hints:

  • (iterate #(sqrt n %) initial-approximation) will give you a seq of approximations.
  • you can use partition to create pairs of subsequent approximations.
  • discard everything not fulfilling the epsilon condition using drop-while
  • get result.

It's probably quite rewarding to solve this using sequences since you get in contact with a lot of useful seq functions.

Note: There is a full solution somewhere in the edit history of this answer. Sorry for that, didn't fully get the "homework" part.

like image 4
xsc Avatar answered Nov 15 '22 08:11

xsc