3

I'm frequently in the position that my code reads like so:

(iterate improve x)

And I'm looking for the first value that no longer is an improvement over the previous. Neither filter nor take-while lend themselves to an obvious solution. However, I'm hesitant to write out:

(loop [current x
       next (improve x)]
  (if (= current next)
    current
    (recur next (improve next))))

or:

(let [improvements (iterate improve x)]
  (->> (map vector improvements (rest improvements))
    (filter (partial apply =))
    (ffirst)))

Because at some point this is becoming repetitive and surely fixed point iteration is such a basic task that there must be some kind of library support somewhere, right?

2 Answers 2

12

You can use reduce and reduced to stop when necessary. reduced wraps the argument in a special object, which reduce is designed to look for and stop processing immediately returning the wrapped value.

(def vals (iterate improve x))

(reduce #(if (= %1 %2) (reduced %1) %2) vals)
Sign up to request clarification or add additional context in comments.

Comments

2

You could use drop-while then first:

(defn still-improving? [[x y]]
  ...)

(->> st
     (iterate transition)
     (partition 2 1)
     (drop-while still-improving?)
     ffirst)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.